BZOJ3069 : [Pa2011]Hard Choice 艰难的选择
在每条边两个点中间加上一个虚拟点代表这条边权,就可以化边权为点权。
把没删掉的边用LCT维护一棵生成树,树边都是桥。
对于一条非树边,把树上对应路径上所有边的权值都修改为0,表示都不是桥。
然后倒着处理询问,对于每次删掉的边,把两点路径上边权都修改为0。
询问等价于查询两点间边权和,若两点连通且路径上不存在桥,则有解。
#include<cstdio> #include<map> const int N=200010,BUF=5000000; char Buf[BUF],*buf=Buf; int a[N],n,m,i,x,fa[N],edge[N][2],ask[N][4],q; struct LCT{int f,son[2],sum,data;bool rev,tag;}T[N]; int father(int x){return fa[x]==x?x:fa[x]=father(fa[x]);} std::map<int,bool>del[N>>1]; inline void swap(int&a,int&b){int c=a;a=b;b=c;} inline bool isroot(int x){return !T[x].f||T[T[x].f].son[0]!=x&&T[T[x].f].son[1]!=x;} inline void rev1(int x){if(!x)return;swap(T[x].son[0],T[x].son[1]),T[x].rev^=1;} inline void makezero1(int x){if(!x)return;T[x].sum=T[x].data=0;T[x].tag=1;} inline void pb(int x){ if(T[x].rev)rev1(T[x].son[0]),rev1(T[x].son[1]),T[x].rev=0; if(T[x].tag)makezero1(T[x].son[0]),makezero1(T[x].son[1]),T[x].tag=0; } inline void up(int x){T[x].sum=T[x].data|T[T[x].son[0]].sum|T[T[x].son[1]].sum;} inline void rotate(int x){ int y=T[x].f,w=T[y].son[1]==x; T[y].son[w]=T[x].son[w^1]; if(T[x].son[w^1])T[T[x].son[w^1]].f=y; if(T[y].f){ int z=T[y].f; if(T[z].son[0]==y)T[z].son[0]=x;else if(T[z].son[1]==y)T[z].son[1]=x; } T[x].f=T[y].f;T[x].son[w^1]=y;T[y].f=x;up(y); } inline void splay(int x){ int s=1,i=x,y;a[1]=i; while(!isroot(i))a[++s]=i=T[i].f; while(s)pb(a[s--]); while(!isroot(x)){ y=T[x].f; if(!isroot(y)){if((T[T[y].f].son[0]==y)^(T[y].son[0]==x))rotate(x);else rotate(y);} rotate(x); } up(x); } inline void access(int x){for(int y=0;x;y=x,x=T[x].f)splay(x),T[x].son[1]=y,up(x);} inline void makeroot(int x){access(x);splay(x);rev1(x);} inline void link(int x,int y){makeroot(x);T[x].f=y;access(x);} inline void makezero(int x,int y){ if(father(x)!=father(y)){ fa[father(x)]=father(y); n++; T[n].sum=T[n].data=1; link(x,n);link(n,y); return; } makeroot(x); access(y); splay(x); makezero1(x); } inline int getsum(int x,int y){ if(father(x)!=father(y))return 1; makeroot(x); access(y); splay(x); return T[x].sum; } inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;} int main(){ fread(Buf,1,BUF,stdin);read(n);read(m);read(q); for(i=1;i<=n;i++)fa[i]=i; for(i=1;i<=m;i++){ read(edge[i][0]);read(edge[i][1]); if(edge[i][0]>edge[i][1])swap(edge[i][0],edge[i][1]); } for(i=1;i<=q;i++){ while(*buf!='Z'&&*buf!='P')buf++; ask[i][0]=x=*buf=='P',buf++; read(ask[i][1]);read(ask[i][2]); if(ask[i][1]>ask[i][2])swap(ask[i][1],ask[i][2]); if(!x)del[ask[i][1]][ask[i][2]]=1; } for(i=1;i<=m;i++)if(!del[edge[i][0]][edge[i][1]])if(father(edge[i][0])!=father(edge[i][1])){ fa[father(edge[i][0])]=father(edge[i][1]); n++; T[n].sum=T[n].data=1; link(edge[i][0],n);link(n,edge[i][1]); del[edge[i][0]][edge[i][1]]=1; } for(i=1;i<=m;i++)if(!del[edge[i][0]][edge[i][1]])makezero(edge[i][0],edge[i][1]); for(i=q;i;i--)if(!ask[i][0])makezero(ask[i][1],ask[i][2]);else ask[i][3]=getsum(ask[i][1],ask[i][2]); for(i=1;i<=q;i++)if(ask[i][0])puts(ask[i][3]?"NIE":"TAK"); return 0; }