• [bzoj3514]Codechef MARCH14 GERALD07加强版


    感觉这题是真的神,,太瓜了根本想不到。

    N个点M条边的无向图,询问保留图中编号在$[l,r]$的边的时候图中的联通块个数。


    考虑每条边的贡献。一条边可以使联通块数量-1当且仅当加入这条边之后,不形成环即连接了两个联通块。

    后加入的边如果形成了环呢?那么只要环中最早加入的边还在,就不会做出贡献。

    那么我们按编号从小到大加边,记录对于每条边,加入之后,如果形成环,形成的环中最早也就是编号最小的边是多少;否则就是0。记为$ntr[i]$。(???wtf?)

    也就是说只有询问的$l>ntr[i]$时,边$i$才能做出贡献(当然也要$i leq r$)。

    $ntr[i]$可以用LCT维护。(维护边权,就是把边变成点做就行了。装逼的做法嘛,jcy大爷有写过博客)

    询问区间有多少$ntr[i]<l$的可以用主席树维护。

    然后我是傻逼。LCT在access时候忘了pullup。rotate时候先更新的x,再更新的原父亲。蠢死了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=400010;
    inline int read(){
        int r=0,c=getchar();
        while(!isdigit(c))c=getchar();
        while(isdigit(c))
        r=r*10+c-'0',c=getchar();
        return r;
    }
    int n,m,k,f;
    /****NTR****/
    #define ls ch[x][0]
    #define rs ch[x][1]
    int ch[N][2],fa[N],tot;
    int rev[N],mn[N],w[N],a[N];
    void pd(int x){
        if(rev[x]){
            rev[ls]^=1,rev[rs]^=1;
            rev[x]=0;swap(ls,rs);
        }
    }
    void pp(int x){
        mn[x]=w[x];
        if(ls)mn[x]=min(mn[x],mn[ls]);
        if(rs)mn[x]=min(mn[x],mn[rs]);
    }
    int isroot(int x){
        return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];
    }
    int get(int x){
        return x==ch[fa[x]][1];
    }
    void rotate(int x){
        int y=fa[x],z=fa[y],px=get(x),py=get(y);
        int t=ch[x][px^1];
        if(!isroot(y))ch[z][py]=x;fa[x]=z;
        ch[x][px^1]=y,fa[y]=x;
        ch[y][px]=t,fa[t]=y;
        pp(y);pp(x);
    }
    int s[N],top;
    void splay(int x){
        top=0;s[++top]=x;
        for(int i=x;!isroot(i);i=fa[i])s[++top]=fa[i];
        for(int i=top;i;i--)pd(s[i]);
        while(!isroot(x)){
            int y=fa[x];
            if(!isroot(y))
            rotate(get(x)==get(y)?y:x);
            rotate(x);
        }
    }
    void access(int x){
        for(int las=0;x;las=x,x=fa[x]){
            splay(x);rs=las;pp(x);
        }
    }
    void makeroot(int x){
        access(x);splay(x);rev[x]^=1;
    }
    void link(int x,int y){
        makeroot(x);fa[x]=y;
    }
    void cut(int x,int y){
        makeroot(x);access(y);splay(y);
        fa[x]=ch[y][0]=0;
    }
    int find(int x){
        access(x),splay(x);
        while(ls)x=ls;
        return x;
    }
    int getmin(int x,int y){
        makeroot(x);access(y);splay(y);
        return mn[y];
    }
    int p[N],q[N];
    void init(){
        n=read(),m=read(),k=read(),f=read();
        for(int i=1;i<=n;i++)w[i]=mn[i]=1e9;
        for(int i=1;i<=m;i++)p[i]=read(),q[i]=read();
        for(int i=1;i<=m;i++){
            w[i+n]=mn[i+n]=i;
            int u=p[i],v=q[i];
            if(u==v){
                a[i]=-1;
                continue;
            }
            if(find(u)==find(v)){
                int w=getmin(u,v);
                cut(p[w],w+n);
                cut(w+n,q[w]);
                a[i]=w;
            }
            link(u,i+n);link(i+n,v);
        }
    }
    #undef ls
    #undef rs
    /****hjt***/
    int rt[N],ls[N*40],rs[N*40],sum[N*40],cnt;
    void ins(int &x,int o,int l,int r,int w){
        x=++cnt;
        ls[x]=ls[o],rs[x]=rs[o];sum[x]=sum[o]+1;
        if(l==r)return;
        int mid=l+r>>1;
        if(w<=mid)ins(ls[x],ls[o],l,mid,w);
        else ins(rs[x],rs[o],mid+1,r,w);
    }
    int query(int p,int q,int l,int r,int v){
        if(r<=v)return sum[q]-sum[p];
        if(l>v)return 0;
        int mid=l+r>>1,ret=query(ls[p],ls[q],l,mid,v);
        if(v>mid)ret+=query(rs[p],rs[q],mid+1,r,v);
        return ret;
    }
    void solve(){
        for(int i=1;i<=m;i++)
        ins(rt[i],rt[i-1],0,m,~a[i]?a[i]:m);
        int ans=0;
        while(k--){
            int l=ans^read(),r=ans^read();
            ans=query(rt[l-1],rt[r],0,m,l-1);
            ans=n-ans;
            printf("%d
    ",ans);if(!f)ans=0;
        }
    }
    /****main****/
    int main(){
        init();
        solve();
    }
  • 相关阅读:
    hdu 1443 Joseph 约瑟夫环
    hdu 1568 Fibonacci 对数。。
    UILineBreakMode
    Android RelativeLayout 动态添加组件
    iOS 让view触发点击事件
    读取plist文件数据
    [转]Android获取SD卡视频音频文件
    ubuntu下vim修复
    DMO(DirectX Media Object)的工程创建过程及其调用方式
    《Windows程序设计》笔记 —— Chapter One
  • 原文地址:https://www.cnblogs.com/orzzz/p/8492123.html
Copyright © 2020-2023  润新知