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;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/4681167.html