zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    什么是Redis?
    请写出常用的linux指令
    Maven常用命令有哪些?
    Maven的工程类型有哪些?
    Maven仓库是什么
    什么是Maven?
    Shiro 的优点
    比较 SpringSecurity 和 Shiro
    判断x二进制编码中1的个数的奇偶性
    寻找600851475143的最大素因子的快速算法
  • 原文地址:https://www.cnblogs.com/clrs97/p/4681167.html
Copyright © 2011-2022 走看看