动态树 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);} } }
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); }
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"); } }
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); } }
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)); } } }
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)); } }