SP16549 QTREE6 - Query on a tree VI(LCT)

题意翻译

题目描述

给你一棵n个点的树,编号1~n。每个点可以是黑色,可以是白色。初始时所有点都是黑色。下面有两种操作请你操作给我们看:

0 u:询问有多少个节点v满足路径u到v上所有节点(包括)都拥有相同的颜色
1 u:翻转u的颜色

输入格式

一行一个整数n

接下来n-1行,每行两个整数表示一条边

接下来一行一个整数m表示操作次数

接下来m行,每行两个整数分别表示操作类型和被操作节点 输出格式

对每个询问操作输出相应的结果

 

题解

简单来说,就是维护同色联通块的大小

干脆直接暴力linkcut好了(T上天)

然后来介绍一下(刚学会的)一种维护染色联通块的较为常用的模型

很多与树有关的题目,当边权不好处理时,可以把边权转化为儿子的点权来做

然后这里恰恰相反,要把点权给转化为边权

我们把每一个节点的颜色赋给与它父亲相连的边

弄两个LCT,对应两种颜色,一种颜色的边只有在对应的LCT中才会相连

于是,同色的联通块,就转化为了减去顶部节点后的边的连通块(因为顶部节点在这个LCT是没有向上连边的,说明顶部节点并不是这个颜色,那么他的所有子树并不连通,要断开才行)

然后可以发现,修改点的颜色之后,只要在原来的LCT中cut,在新的LCT上link就行啦

查询怎么做呢?先access,然后findroot,再输出root的实子树大小就行了

ps:1本来没有父亲,但为了方便,可以建一个虚点n+1,令他作为1的父亲就好了

  1 //minamoto
  2 #include<iostream>
  3 #include<cstdio>
  4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  5 char buf[1<<21],*p1=buf,*p2=buf;
  6 inline int read(){
  7     #define num ch-'0'
  8     char ch;bool flag=0;int res;
  9     while(!isdigit(ch=getc()))
 10     (ch=='-')&&(flag=true);
 11     for(res=num;isdigit(ch=getc());res=res*10+num);
 12     (flag)&&(res=-res);
 13     #undef num
 14     return res;
 15 }
 16 char sr[1<<21],z[20];int C=-1,Z;
 17 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
 18 inline void print(int x){
 19     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
 20     while(z[++Z]=x%10+48,x/=10);
 21     while(sr[++C]=z[Z],--Z);sr[++C]='\n';
 22 }
 23 const int N=100005;
 24 int f[N],Next[N<<1],head[N],ver[N<<1],tot,col[N],n,m;
 25 inline void add(int u,int v){
 26     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
 27     ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
 28 }
 29 struct LCT{
 30     int fa[N],ch[N][2],si[N],sum[N];
 31     LCT(){for(int i=1;i<=n+1;++i) sum[i]=1;}
 32     inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
 33     #define lc ch[x][0]
 34     #define rc ch[x][1]
 35     inline void pushup(int x){sum[x]=sum[lc]+sum[rc]+si[x]+1;}
 36     void rotate(int x){
 37         int y=fa[x],z=fa[y],d=ch[y][1]==x;
 38         if(!isroot(y)) ch[z][ch[z][1]==y]=x;
 39         fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y,pushup(y);
 40     }
 41     void splay(int x){
 42         for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){
 43             if(!isroot(y))
 44             ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y);
 45             rotate(x);
 46         }
 47         pushup(x);
 48     }
 49     void access(int x){
 50         for(int y=0;x;x=fa[y=x]){
 51             splay(x);
 52             si[x]+=sum[rc];
 53             si[x]-=sum[rc=y];
 54         }
 55     }
 56     int findroot(int x){
 57         access(x),splay(x);
 58         while(lc) x=lc;
 59         splay(x);
 60         return x;
 61     }
 62     void link(int x){
 63         access(x),splay(x);
 64         int y=fa[x]=f[x];
 65         access(y),splay(y);
 66         si[y]+=sum[x],sum[y]+=sum[x];
 67     }
 68     void cut(int x){
 69         access(x),splay(x);
 70         lc=fa[lc]=0;
 71         pushup(x);
 72     }
 73 }lct[2];
 74 void dfs(int u){
 75     for(int i=head[u];i;i=Next[i]){
 76         int v=ver[i];
 77         if(v==f[u]) continue;
 78         f[v]=u,dfs(v),lct[0].link(v);
 79     }
 80 }
 81 int main(){
 82     //freopen("testdata.in","r",stdin);
 83     n=read();
 84     for(int i=1;i<n;++i){
 85         int u=read(),v=read();
 86         add(u,v);
 87     }
 88     dfs(1);
 89     f[1]=n+1,lct[0].link(1);
 90     m=read();
 91     while(m--){
 92         int op=read(),u=read();
 93         if(op) lct[col[u]].cut(u),lct[col[u]^=1].link(u);
 94         else{
 95             int v=lct[col[u]].findroot(u);
 96             print(lct[col[u]].sum[lct[col[u]].ch[v][1]]);
 97         }
 98     }
 99     Ot();
100     return 0;
101 }

 

posted @ 2018-08-07 12:57  bztMinamoto  阅读(310)  评论(0编辑  收藏  举报
Live2D