• SP16549 QTREE6


    题意翻译

    题目描述

    给你一棵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]='
    ';
     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 }
  • 相关阅读:
    批处理手动设置电脑的ip
    用shell脚本生成日志文件
    编译小米mini openwrt
    Jackson 时间格式化,时间注解 @JsonFormat 用法、时差问题说明
    swagger注释API详细说明
    com.rabbitmq.client.impl.Frame.readFrom(Frame.java:95)
    在Java中如何高效判断数组中是否包含某个元素
    阿里云服务器端口开放对外访问权限
    macos 安装telnet命令
    在 Docker 上配置 Oracle
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9436367.html
Copyright © 2020-2023  润新知