动态树 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\n");
            else printf("No\n");
        }
        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\n",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\n");
        else printf("No\n");
    }
}
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\n",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\n",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\n",la=n-ask(rt[r],1,m,l,r));
    }
}
View Code

 

posted @ 2015-08-18 13:07  Rivendell  阅读(353)  评论(0编辑  收藏  举报