zoukankan      html  css  js  c++  java
  • 动态树 LCT

    bzoj2049 洞穴探测

    题目大意:lct(link,cut,判联通)。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define maxnode 10005
    using namespace std;
    struct lct{
        int fa[maxnode],ch[maxnode][2],rev[maxnode],zh[maxnode];
        void init()
        {
            memset(fa,0,sizeof(fa));
            memset(ch,0,sizeof(ch));
            memset(rev,0,sizeof(rev));
        }
        bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
        int isd(int x){return x==ch[fa[x]][1];}
        void pushdown(int x)
        {
            int l,r;l=ch[x][0];r=ch[x][1];
            if (rev[x])
            {
                rev[x]^=1;rev[l]^=1;rev[r]^=1;
                swap(ch[x][0],ch[x][1]);
            }
        }
        void rotate(int x)
        {
            int y,z,d,l,r;y=fa[x];z=fa[y];
            if (ch[y][0]==x) l=0;
            else l=1; r=l^1;
            if (!isroot(y))
            {
                if (ch[z][0]==y) ch[z][0]=x;
                else ch[z][1]=x;
            }
            fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
            ch[y][l]=ch[x][r];ch[x][r]=y;
        }
        void splay(int x)
        {
            int i,top=0,y,z;zh[++top]=x;
            for (i=x;!isroot(i);i=fa[i]) zh[++top]=fa[i];
            for (i=top;i>=1;--i) pushdown(zh[i]);
            while(!isroot(x))
            {
                y=fa[x];z=fa[y];
                if (!isroot(y))
                {
                    if (isd(x)==isd(y)) rotate(y);
                    else rotate(x);
                }
                rotate(x);
            }
        }
        void access(int x)
        {
            int y=0;
            while(x){splay(x);ch[x][1]=y;y=x;x=fa[x];}
        }
        void makert(int x){access(x);splay(x);rev[x]^=1;}
        void link(int x,int y){makert(x);fa[x]=y;access(x);}
        void cut(int x,int y)
        {
           makert(x);access(y);splay(y);
           ch[y][0]=fa[x]=0;
        }
        int find(int x)
        {
            access(x);splay(x);
            int y=x;
            while(ch[y][0]) y=ch[y][0];
            return y;
        }
    }tree;
    char ss[10];
    int main()
    {
        int n,m,i,j,u,v;
        scanf("%d%d",&n,&m);tree.init();
        for (i=1;i<=m;++i)
        {
            scanf("%s",&ss);
            if (ss[0]=='Q')
            {
                scanf("%d%d",&u,&v);
                if (tree.find(u)==tree.find(v)) printf("Yes
    ");
                else printf("No
    ");
            }
            if (ss[0]=='C'){scanf("%d%d",&u,&v);tree.link(u,v);}
            if (ss[0]=='D'){scanf("%d%d",&u,&v);tree.cut(u,v);}
        }
    }
    View Code

    bzoj2594 水管局长

    题目大意:给定一个无向图,操作:1)删除连接两点的边;2)求两点间最大边最小路径

    思路:相当于维护一个最小生成树的最大边,删边可以用倒着的加边,加边的时候看两点间的最大值是否比这个边权大,然后更新一下。

    求两点间最大边权的时候把x做根,yaccess、splay之后,y的子树最大值就是了。

    (map姿势比手写二分慢;不需要维护最大值,只需要最大值的位置,会快一些)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100005
    #define M 1100005
    using namespace std;
    struct use{
        int x,y,va,cn,po;
        bool operator<(const use&xx)const{return va<xx.va;}
    }ed[M]={0};
    int in(){
        char ch=getchar();int x=0;
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x;}
    struct uu{int k,x,y,ans,id;}ask[N]={0};
    int tot=0,n,m,q,ff[N];
    int cmp(const use&x,const use&y){return x.po<y.po;}
    int cmp2(const use&x,const use&y){return (x.x==y.x ? x.y<y.y : x.x<y.x);}
    struct lct{
        int fa[M],rev[M],ch[M][2],zh[M],v[M],id[M];
        inline int isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
        inline int isd(int x){return x==ch[fa[x]][1];}
        inline void updata(int x){
            int l,r;l=ch[x][0];r=ch[x][1];id[x]=x;
            if (v[id[l]]>v[id[x]]) id[x]=id[l];
            if (v[id[r]]>v[id[x]]) id[x]=id[r];}
        inline void pushdown(int x){
            int l,r;l=ch[x][0];r=ch[x][1];
            if (rev[x]){
                rev[l]^=1;rev[r]^=1;rev[x]^=1;
                swap(ch[x][0],ch[x][1]);
            }}
        inline void rotate(int x){
            int y,z,l,r;y=fa[x];z=fa[y];
            if (x==ch[y][0]) l=0;
            else l=1; r=l^1;
            if (!isroot(y)){
                if (ch[z][0]==y) ch[z][0]=x;
                else ch[z][1]=x;
            }fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
            ch[y][l]=ch[x][r];ch[x][r]=y;
            updata(y);updata(x);}
        inline void splay(int x){
            int y,z;zh[zh[0]=1]=x;
            for (y=x;!isroot(y);y=fa[y]) zh[++zh[0]]=fa[y];
            for (;zh[0];--zh[0]) pushdown(zh[zh[0]]);
            while(!isroot(x)){
                y=fa[x];z=fa[y];
                if (!isroot(y)){
                  if (isd(y)==isd(x)) rotate(y);
                  else rotate(x);
                }rotate(x);
            }}
        inline void access(int x){int y=0;while(x){splay(x);ch[x][1]=y;updata(x);y=x;x=fa[x];}}
        inline void makert(int x){access(x);splay(x);rev[x]^=1;}
        inline void link(int x,int y){makert(x);fa[x]=y;access(x);}
        inline void cut(int x,int y){
            makert(x);access(y);splay(y);
            ch[y][0]=fa[x]=0;}
        inline int query(int x,int y){
            makert(x);access(y);splay(y);
            return id[y];}
    }tr;
    inline int find(int x,int y){
        int l,r,mid;l=1;r=m;
        while(l<=r){
            mid=l+r>>1;
            if (ed[mid].x<x||(ed[mid].x==x&&ed[mid].y<y)) l=mid+1;
            else{
                if (ed[mid].x==x&&ed[mid].y==y) return mid;
                else r=mid-1;
            }
        }return l;}
    inline int root(int x){return (x==ff[x] ? ff[x] : ff[x]=root(ff[x]));}
    inline void pre(){
        int i,j=0,r1,r2;
        sort(ed+1,ed+m+1);
        for (i=1;i<=n;++i) ff[i]=i;
        for (i=1;i<=m;++i){
            if (ed[i].cn) continue;
            r1=root(ed[i].x);r2=root(ed[i].y);
            if (r1==r2) continue;++j;
            ff[r1]=r2;tr.id[ed[i].po+n]=ed[i].po+n;
            tr.v[ed[i].po+n]=ed[i].va;
            tr.link(ed[i].x,ed[i].po+n);
            tr.link(ed[i].y,ed[i].po+n);
            if (j==n-1) break;
        }sort(ed+1,ed+m+1,cmp);}
    int main(){
        int i,j,xx;n=in();m=in();q=in();
        for (i=1;i<=m;++i){
            ed[i].x=in();ed[i].y=in();ed[i].va=in();
        }sort(ed+1,ed+m+1,cmp2);
        for (i=1;i<=m;++i) ed[i].po=i;
        for (i=1;i<=q;++i){
            ask[i].k=in();ask[i].x=in();ask[i].y=in();
            if (ask[i].k==2) ed[ask[i].id=find(ask[i].x,ask[i].y)].cn=1;
        }for (pre(),i=q;i;--i){
            if (ask[i].k==1) ask[i].ans=tr.v[tr.query(ask[i].x,ask[i].y)];
            else{
                xx=tr.query(ask[i].x,ask[i].y);
                j=ask[i].id;
                if (tr.v[xx]>ed[j].va){
                    tr.cut(ed[xx-n].x,xx);
                    tr.cut(xx,ed[xx-n].y);
                    tr.v[j+n]=ed[j].va;tr.id[j+n]=j+n;
                    tr.link(ed[j].x,j+n);tr.link(ed[j].y,j+n);
                }
            }
        }for (i=1;i<=q;++i)
          if (ask[i].k==1) printf("%d
    ",ask[i].ans);
    }
    View Code

    bzoj4025 二分图

    题目大意:给定一张无向图,每条边有添加和删除的时间,判断每个时间是否是二分图。

    思路:判断二分图就相当于判断是否有奇环,用lct维护删除时间的最大生成树(保证了操作时树边是最后删的,需要维护子树大小、最小权值!!!)。填边的时候:如果两端点没有联通,就直接填;如果联通了,就判断是否构成奇环,都要维护最大生成树,如果是奇环还要把没加入树的那条边用map维护一下。删边的时候,如果两端点联通并且是树边直接删;如果是map里的就把map这条边清掉。判断是否是二分图就是看map中有无边。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #define N 400005
    using namespace std;
    struct use{int x,y,ts,te;}edge[N];
    struct uu{int id,t,k;}ed[N];//t=min k=sum
    int cmp(const uu&x,const uu&y){return (x.t==y.t ? x.k<y.k : x.t<y.t);}
    map<int,int> cnt[N];
    int cl=0,tot=0,n;
    int in(){
        char ch=getchar();int x=0;
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x;}
    struct lct{
        int fa[N],ch[N][2],rev[N],zh[N],id[N],v[N],siz[N];
        void init(){
            memset(fa,0,sizeof(fa));
            memset(ch,0,sizeof(ch));
            memset(rev,0,sizeof(rev));
            memset(siz,0,sizeof(siz));
            memset(v,127,sizeof(v));}
        int isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
        int isd(int x){return x==ch[fa[x]][1];}
        void updata(int x){
            int l,r;id[x]=x;siz[x]=(x>n ? 0 : 1);
            l=ch[x][0];r=ch[x][1];
            if (v[id[l]]<v[id[x]]) id[x]=id[l];
            if (v[id[r]]<v[id[x]]) id[x]=id[r];
            siz[x]+=siz[l]+siz[r];}
        void pushdown(int x){
            if (rev[x]){
                int l,r;l=ch[x][0];r=ch[x][1];
                rev[x]^=1;rev[l]^=1;rev[r]^=1;
                swap(ch[x][0],ch[x][1]);
            }}
        void rotate(int x){
            int y,z,l,r;y=fa[x];z=fa[y];
            if (x==ch[y][0]) l=0;
            else l=1; r=l^1;
            if (!isroot(y)){
                if (y==ch[z][0]) ch[z][0]=x;
                else ch[z][1]=x;
            }fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
            ch[y][l]=ch[x][r];ch[x][r]=y;
            updata(y);updata(x);}
        void splay(int x){
            int i,j,y,z;zh[zh[0]=1]=x;
            for (i=x;!isroot(i);i=fa[i]) zh[++zh[0]]=fa[i];
            for (;zh[0];--zh[0]) pushdown(zh[zh[0]]);
            while(!isroot(x)){
                y=fa[x];z=fa[y];
                if (!isroot(y)){
                    if (isd(y)==isd(x)) rotate(y);
                    else rotate(x);
                }rotate(x);
            }}
        void access(int x){int y=0;while(x){splay(x);ch[x][1]=y;updata(x);y=x;x=fa[x];}}
        void makert(int x){access(x);splay(x);rev[x]^=1;}
        void cut(int x,int y){
            makert(x);access(y);splay(y);
            ch[y][0]=fa[x]=0;updata(y);}
        void link(int x,int y){makert(x);fa[x]=y;access(x);}
        int find(int x){
            access(x);splay(x);int y;
            for(y=x;ch[y][0];y=ch[y][0]);
            return y;}
        bool connect(int x,int y){return find(x)==find(y);}
        uu query(int x,int y){
            makert(x);access(y);splay(y);
            return (uu){0,id[y],siz[y]};}
        void add(uu x){
            use xx=edge[x.id];
            if (x.k){
              if (!connect(xx.x,xx.y)){
                v[x.id+n]=xx.te;
                link(xx.x,x.id+n);link(xx.y,x.id+n);
              }else{
                  uu c=query(xx.x,xx.y);
                  if (c.k%2){
                      if (xx.te>v[c.t]){
                          cut(edge[c.t-n].x,c.t);
                          cut(edge[c.t-n].y,c.t);
                          link(xx.x,x.id+n);link(xx.y,x.id+n);
                          cnt[edge[c.t-n].x][edge[c.t-n].y]=cnt[edge[c.t-n].y][edge[c.t-n].x]=1;
                          ++cl;
                      }else{cnt[xx.x][xx.y]=cnt[xx.y][xx.x]=1;++cl;}
                  }else{
                      if (xx.te>v[c.t]){
                          cut(edge[c.t-n].x,c.t);
                          cut(edge[c.t-n].y,c.t);
                          link(xx.x,x.id+n);link(xx.y,x.id+n);
                    }
                  }
              }
            }else{
                if (cnt[xx.x][xx.y]){--cl;cnt[xx.x][xx.y]=cnt[xx.y][xx.x]=0;}
                else if (connect(xx.x,xx.y)){cut(xx.x,x.id+n);cut(xx.y,x.id+n);}
            }
        }
    }tr;
    int main(){
        int m,t,i,j,u,v,x,y;tr.init();
        n=in();m=in();t=in();
        for (i=1;i<=m;++i){
            u=in();v=in();x=in();y=in();
            edge[i]=(use){u,v,x,y};
            if (x!=y){ed[++tot]=(uu){i,x,1};ed[++tot]=(uu){i,y,0};}
        }sort(ed+1,ed+tot+1,cmp);
        for (j=1,i=0;i<t;++i){
            while(j<=tot&&ed[j].t==i) tr.add(ed[j++]);
            if (!cl) printf("Yes
    ");
            else printf("No
    ");
        }
    }
    View Code

    bzoj1453 双面棋盘

    题目大意:给定一个棋盘,格子有两种颜色,认为上下左右相邻的同色格子是一个联通块,每次操作改一个格子的颜色,问改后黑白联通块的个数。

    思路:倒着扫一遍操作,维护出边的删除时间,用lct维护删除时间最大生成树,然后全局维护黑白块的个数。

    注意:排序后的数组下标要对应。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 205
    #define M 200005
    #define E 150005
    #define inf 2100000000
    using namespace std;
    struct use{int x,y;}ask[E],gi[N*N];
    struct edge{
        int u,v,id,k,t,po,co;
        bool operator<(const edge&x)const{return (id==x.id ? k<x.k : id<x.id);}
    }ed[E];
    int id[N][N],tot=0,n,ns[N][N],ai[N][N],ti[N][N][4],dx[4]={1,0,0,-1},dy[4]={0,1,-1,0},
        ans[M],cntb,cntw,eid[N][N][4],tt=0,nt=0,it[N][N][4]={0},dui[M];
    int in(){
        char ch=getchar();int x=0;
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x;}
    int pos(int x,int y){
        if (y-x==n) return 0;
        if (y-x==1) return 1;
        if (x-y==1) return 2;
        return 3;}
    struct lct{
        int fa[M],ch[M][2],rev[M],v[M],md[M],zh[M];
        void init(){
            memset(fa,0,sizeof(fa));
            memset(ch,0,sizeof(ch));
            memset(rev,0,sizeof(rev));
            memset(v,127,sizeof(v));
            memset(md,0,sizeof(md));}
        int isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
        int isd(int x){return ch[fa[x]][1]==x;}
        void pushdown(int x){
            int l,r;l=ch[x][0];r=ch[x][1];
            if (rev[x]){
                rev[x]^=1;rev[l]^=1;rev[r]^=1;
                swap(ch[x][0],ch[x][1]);
            }}
        void updata(int x){
            int l,r;l=ch[x][0];r=ch[x][1];md[x]=x;
            if (v[md[l]]<v[md[x]]) md[x]=md[l];
            if (v[md[r]]<v[md[x]]) md[x]=md[r];}
        void rotate(int x){
            int l,r,y,z;y=fa[x];z=fa[y];
            if (x==ch[y][0]) l=0;
            else l=1; r=l^1;
            if (!isroot(y)){
                if (y==ch[z][0]) ch[z][0]=x;
                else ch[z][1]=x;
            }fa[x]=z;ch[y][l]=ch[x][r];
            fa[ch[x][r]]=y;ch[x][r]=y;fa[y]=x;
            updata(y);updata(x);}
        void splay(int x){
            int top,i,j,y,z;zh[top=1]=x;
            for (i=x;!isroot(i);i=fa[i]) zh[++top]=fa[i];
            for (i=top;i;--i) pushdown(zh[i]);
            while(!isroot(x)){
                y=fa[x];z=fa[y];
                if (!isroot(y)){
                  if (isd(x)==isd(y)) rotate(y);
                  else rotate(x);
                }rotate(x);
            }
        }
        void access(int x){int y=0;while(x){splay(x);ch[x][1]=y;updata(x);y=x;x=fa[x];}}
        void makert(int x){access(x);splay(x);rev[x]^=1;}
        bool cut(int x,int y){
            makert(x);access(y);splay(y);
            if (fa[x]==y){fa[x]=ch[y][0]=0;updata(y);return true;}
            return false;}
        void link(int x,int y){makert(x);fa[x]=y;access(x);}
        int find(int x){
            int y;access(x);splay(x);
            for (y=x;ch[y][0];y=ch[y][0]);
            return y;}
        bool connect(int x,int y){return find(x)==find(y);}
        int query(int x,int y){
            makert(x);access(y);splay(y);
            return md[y];}
        void add(edge x){
            int ci,di;
            if (!x.k){
                x.po=it[gi[x.u].x][gi[x.u].y][pos(x.u,x.v)];
                if(x.po){
                    cut(x.u,x.po+tt);cut(x.v,x.po+tt);
                    if (x.co) ++cntb;
                    else ++cntw;
                    it[gi[x.u].x][gi[x.u].y][pos(x.u,x.v)]=
                    it[gi[x.v].x][gi[x.v].y][pos(x.v,x.u)]=0;
                }
            }else{
                if (!connect(x.u,x.v)){
                    v[x.po+tt]=x.t;
                    if (x.co) --cntb;
                    else --cntw;
                    link(x.u,x.po+tt);link(x.v,x.po+tt);
                    it[gi[x.u].x][gi[x.u].y][pos(x.u,x.v)]=
                    it[gi[x.v].x][gi[x.v].y][pos(x.v,x.u)]=x.po;
                }else{
                    ci=query(x.u,x.v);
                    if (v[ci]<x.t){
                        di=dui[ci-tt];
                        cut(ed[di].u,ci);cut(ed[di].v,ci);
                        int uu,vv;uu=ed[di].u;vv=ed[di].v;
                        it[gi[uu].x][gi[uu].y][pos(uu,vv)]=
                        it[gi[vv].x][gi[vv].y][pos(vv,uu)]=0;
                        v[x.po+tt]=x.t;
                        link(x.u,x.po+tt);link(x.v,x.po+tt);
                        it[gi[x.u].x][gi[x.u].y][pos(x.u,x.v)]=
                        it[gi[x.v].x][gi[x.v].y][pos(x.v,x.u)]=x.po;
                    }
                }
            }
        }
    }tr;
    int main(){
        int m,i,j,k,x,y,xx,yy;n=in();
        for (cntb=cntw=tt=0,i=1;i<=n;++i)
            for (j=1;j<=n;++j){
                  ns[i][j]=in();
                ai[i][j]=ns[i][j];id[i][j]=++tt;
                gi[tt]=(use){i,j};
                if (ai[i][j]) ++cntb;
                else ++cntw;
            }m=in();
        for (i=1;i<=m;++i){
            ask[i].x=in();ask[i].y=in();
            ns[ask[i].x][ask[i].y]^=1;
        }memset(ti,127/3,sizeof(ti));
        tr.init();
        for (i=m;i;--i){
            x=ask[i].x;y=ask[i].y;
            for (k=0;k<4;++k){
                xx=x+dx[k];yy=y+dy[k];
                if (xx<=0||xx>n||yy<=0||yy>n) continue;
                if (ns[x][y]==ns[xx][yy]){
                    ed[++tot]=(edge){id[x][y],id[xx][yy],i,1,ti[x][y][k],tot,ns[x][y]};
                }else{
                    ed[++tot]=(edge){id[x][y],id[xx][yy],i,0,ti[x][y][k],tot,ns[xx][yy]};
                    ti[x][y][k]=ti[xx][yy][3-k]=i;
                }
            }ns[x][y]^=1;
        }sort(ed+1,ed+tot+1);nt=tot;
        for (i=1;i<=tot;++i) dui[ed[i].po]=i;
        for (x=1;x<=n;++x)
          for (y=1;y<=n;++y)
              for (k=0;k<2;++k){
                  xx=x+dx[k];yy=y+dy[k];
                  if (xx<=0||xx>n||yy<=0||yy>n) continue;
                  if (ns[x][y]==ns[xx][yy]){
                    ed[++tot]=(edge){id[x][y],id[xx][yy],0,1,ti[x][y][k],tot,ns[x][y]};
                    tr.add(ed[tot]);
                    dui[tot]=tot;
                }
              }
        for (j=1,i=1;i<=m;++i){
            for (;j<=nt&&ed[j].id==i;++j) tr.add(ed[j]);
            if (ns[ask[i].x][ask[i].y]){++cntw;--cntb;}
            else{++cntb;--cntw;}
            ns[ask[i].x][ask[i].y]^=1;
            printf("%d %d
    ",cntb,cntw);
        }
    }
    View Code

    bzoj2816 网络

    题目大意:一张图,边有c种颜色,要保证没有同色环且同一点连出去至多有两条同色边。支持:(1)改变点权;(2)改变边的颜色;(3)查询某两点间某种颜色的简单路径的点权最大值。

    思路:建c棵lct,维护连通性和点权最大值。

    注意:1)边的颜色可能不变,判断同色边的时候不管;

         2)splay中改变点权要先splay点,改变点权,再updata。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 10005
    #define M 100005
    #define up 15
    using namespace std;
    struct use{
        int u,v,w;
        bool operator<(const use&a)const{return (u==a.u ? v<a.v : u<a.u);}
    }ed[M];
    int n,m,vi[N]={0},cnt[N][up]={0},zh[N];
    int in(){
        char ch=getchar();int x=0;
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x;}
    int ef(int u,int v){
        if (u>v) swap(u,v);
        int l,r,mid;l=1;r=m;
        while(l!=r){
            mid=(l+r)>>1;
            if (ed[mid].u<u||(ed[mid].u==u&&ed[mid].v<v)) l=mid+1;
            else r=mid;
        }return l;}
    struct lct{
        int fa[N],ch[N][2],rev[N],md[N];
        bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
        bool isd(int x){return ch[fa[x]][1]==x;}
        void updata(int x){
            int l,r;l=ch[x][0];r=ch[x][1];md[x]=x;
            if (vi[md[l]]>vi[md[x]]) md[x]=md[l];
            if (vi[md[r]]>vi[md[x]]) md[x]=md[r];}
        void pushdown(int x){
            if (rev[x]){
                int l,r;l=ch[x][0];r=ch[x][1];
                rev[x]^=1;rev[l]^=1;rev[r]^=1;
                swap(ch[x][0],ch[x][1]);
            }}
        void rotate(int x){
            int l,r,y,z;y=fa[x];z=fa[y];
            if (ch[y][0]==x) l=0;
            else l=1; r=l^1;
            if (!isroot(y)){
                if (ch[z][0]==y) ch[z][0]=x;
                else ch[z][1]=x;
            }fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
            ch[y][l]=ch[x][r];ch[x][r]=y;
            updata(y);updata(x);}
        void splay(int x){
            int i,j,zt,y,z;zh[zt=1]=x;
            for (i=x;!isroot(i);i=fa[i]) zh[++zt]=fa[i];
            for (;zt;--zt) pushdown(zh[zt]);
            while(!isroot(x)){
                y=fa[x];z=fa[y];
                if (!isroot(y)){
                    if (isd(x)==isd(y)) rotate(y);
                    else rotate(x);
                }rotate(x);
            }}
        void access(int x){int y=0;while(x){splay(x);ch[x][1]=y;updata(x);y=x;x=fa[x];}}
        void makert(int x){access(x);splay(x);rev[x]^=1;}
        void cut(int x,int y){
            makert(x);access(y);splay(y);
            fa[x]=ch[y][0]=0;updata(y);}
        void link(int x,int y){makert(x);fa[x]=y;access(x);}
        int find(int x){
            access(x);splay(x);
            for (;ch[x][0];x=ch[x][0]);
            return x;}
        int ask(int x,int y){
            if (find(x)!=find(y)) return -1;
            makert(x);access(y);splay(y);
            return vi[md[y]];}
    }tr[up];
    int main(){
        int c,t,u,v,w,i,j,k,ww;
        n=in();m=in();c=in();t=in();
        memset(tr,0,sizeof(tr));
        for (i=1;i<=n;++i) vi[i]=in();
        for (i=1;i<=m;++i){
            u=in();v=in();w=in();
            if (u>v) swap(u,v);
            ed[i]=(use){u,v,w};
            ++cnt[u][w];++cnt[v][w];
            tr[w].link(u,v);
        }sort(ed+1,ed+m+1);
        for (i=1;i<=t;++i){
            k=in();
            if (k==0){
                u=in();v=in();
                for (j=0;j<c;++j) tr[j].splay(u);
                for (j=0,vi[u]=v;j<c;++j) tr[j].updata(u);
            }if (k==1){
                u=in();v=in();w=in();
                if (u>v) swap(u,v);
                j=ef(u,v);ww=ed[j].w;
                if (ed[j].u!=u||ed[j].v!=v){puts("No such edge.");continue;}
                if (ww==w){puts("Success.");continue;}
                if (cnt[u][w]>=2||cnt[v][w]>=2){
                    puts("Error 1.");continue;
                }if (tr[w].find(u)==tr[w].find(v)){
                    puts("Error 2.");continue;
                }--cnt[u][ww];--cnt[v][ww];
                ++cnt[u][w];++cnt[v][w];
                tr[ww].cut(u,v);tr[w].link(u,v);
                ed[j].w=w;puts("Success.");
            }if (k==2){
                w=in();u=in();v=in();
                printf("%d
    ",tr[w].ask(u,v));
            }
        }
    }
    View Code

    bzoj3514 Codechef MARCH14 GERALD07加强版

    题目大意:给定一张无向图,每次询问编号L~R的边形成图的联通块个数。

    思路:点数-生成树的边数是联通块个数。考虑维护L~R间的边的树边个数,维护编号的最大生成树,查询的时候要查1~R的树中在L~R的边的条数,建立主席树,查询。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 400005
    #define M 8000005
    using namespace std;
    struct tree{int l,r,sz;}tr[M];
    struct edge{int u,v;}ed[N];
    int n,m,rt[N]={0},tt=0,inf;
    void ins(int la,int &i,int l,int r,int x,int y){
        tr[i=++tt]=tr[la];tr[i].sz+=y;
        if (l==r) return;
        int mid=(l+r)>>1;
        if (x<=mid) ins(tr[la].l,tr[i].l,l,mid,x,y);
        else ins(tr[la].r,tr[i].r,mid+1,r,x,y);}
    int ask(int i,int l,int r,int ll,int rr){
        if (ll<=l&&r<=rr) return tr[i].sz;
        int sm=0,mid=(l+r)>>1;
        if (ll<=mid) sm+=ask(tr[i].l,l,mid,ll,rr);
        if (rr>mid) sm+=ask(tr[i].r,mid+1,r,ll,rr);
        return sm;}
    struct use{
        int fa[N],md[N],rev[N],ch[N][2],zh[N],vi[N];
        void init(){
            memset(fa,0,sizeof(fa));
            memset(rev,0,sizeof(rev));
            memset(ch,0,sizeof(ch));
            memset(vi,127/3,sizeof(vi));
            inf=vi[0];}
        bool isroot(int u){return u!=ch[fa[u]][0]&&u!=ch[fa[u]][1];}
        bool isd(int u){return u==ch[fa[u]][1];}
        void pushdown(int u){
            if (rev[u]){
                int l,r;l=ch[u][0];r=ch[u][1];
                rev[l]^=1;rev[r]^=1;rev[u]^=1;
                swap(ch[u][0],ch[u][1]);
            }
        }
        void updata(int u){
            int l,r;l=ch[u][0];r=ch[u][1];md[u]=u;
            if (vi[md[l]]<vi[md[u]]) md[u]=md[l];
            if (vi[md[r]]<vi[md[u]]) md[u]=md[r];
        }
        void rotate(int x){
            int y,z,l,r;y=fa[x];z=fa[y];
            if (x==ch[y][0]) l=0;
            else l=1; r=l^1;
            if (!isroot(y)){
                if (y==ch[z][0]) ch[z][0]=x;
                else ch[z][1]=x;
            }fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
            ch[y][l]=ch[x][r];ch[x][r]=y;
            updata(y);updata(x);}
        void splay(int x){
            int i,zt,y,z;zh[zt=1]=x;
            for (i=x;!isroot(i);i=fa[i]) zh[++zt]=fa[i];
            for (;zt;--zt) pushdown(zh[zt]);
            while(!isroot(x)){
                y=fa[x];z=fa[y];
                if (!isroot(y)){
                    if (isd(x)==isd(y)) rotate(y);
                    else rotate(x);
                }rotate(x);
            }
        }
        void access(int x){int y=0;while(x){splay(x);ch[x][1]=y;updata(x);y=x;x=fa[x];}}
        void makert(int x){access(x);splay(x);rev[x]^=1;}
        void link(int x,int y){makert(x);fa[x]=y;access(x);}
        void cut(int x,int y){
            makert(x);access(y);splay(y);
            fa[x]=ch[y][0]=0;updata(y);}
        int find(int x){
            access(x);splay(x);
            for (;ch[x][0];x=ch[x][0]);
            return x;}
        bool connect(int x,int y){return find(x)==find(y);}
        int query(int x,int y){
            makert(x);access(y);splay(y);
            return md[y];}
        void add(int x,int y,int id){
            int u;rt[id]=rt[id-1];
            vi[id+n]=id;
            if (x==y) return;
            if (connect(x,y)){
                u=query(x,y)-n;
                cut(ed[u].u,u+n);cut(ed[u].v,u+n);
                ins(rt[id],rt[id],1,m,u,-1);
            }link(x,id+n);link(id+n,y);
            ins(rt[id],rt[id],1,m,id,1);
        }
    }lct;
    int main(){
        int i,k,kk,u,v,la=0,l,r;
        memset(tr,0,sizeof(tr));
        scanf("%d%d%d%d",&n,&m,&k,&kk);
        lct.init();
        for (i=1;i<=m;++i){
            scanf("%d%d",&u,&v);
            ed[i]=(edge){u,v};
            lct.add(u,v,i);
        }for (i=1;i<=k;++i){
            scanf("%d%d",&l,&r);
            if (kk){l^=la;r^=la;}
            printf("%d
    ",la=n-ask(rt[r],1,m,l,r));
        }
    }
    View Code
  • 相关阅读:
    二分查找练习
    Linux中Buffer和Cache的区别
    c++设计模式之单例模式
    c++设计模式之工厂模式
    C++中内存泄漏的几种情况
    snprintf
    命名空间和模块化编程1
    避免内存泄漏
    静态对象强制类型转换
    副本构造器
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4739132.html
Copyright © 2011-2022 走看看