这道题目是维护边权信息,于是我就把原树中边变成点维护。由于颜色不超过30种,可以每个点维护一个int整数代表自己子树的颜色集合,pushup时并(就是 | 这个运算符)一下即可。对于每个原树中的点,颜色一定要保持为0。pushdown时,要判断一下,使得原树中的点颜色始终保持为0,不能被修改,不然就会出错。具体实现见代码。
接下来就好办了,操作1就先cut再link,操作2就先提取这段路径再打懒标,操作3就先提取路径再求一下颜色总数即可。
至于操作1的判断祖孙关系,暂时不知道怎么快速判断,于是我只好在原树中暴力判断,结果居然过了。。。事实上,当树变得很高时,我的打法会被卡。
代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=50005;
int n,m,op,u,v,c,cnt,ans,pa[N],rt[N];
int fa[N*2],ch[N*2][2],rev[N*2],tag[N*2],sumv[N*2],siz[N*2],val[N*2],stk[N*2];
int head[N*2],to[N*4],nxt[N*4];
void adde(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void dfs(int u){int v;for(int i=head[u];i;i=nxt[i]){v=to[i];if(v!=fa[u]){fa[v]=u;dfs(v);}}
}
bool isroot(int u){return ch[fa[u]][0]!=u&&ch[fa[u]][1]!=u;
}
int which(int u){return u==ch[fa[u]][1];
}
void pushup(int u){sumv[u]=1<<val[u];siz[u]=1;if(ch[u][0]){sumv[u]|=sumv[ch[u][0]];siz[u]+=siz[ch[u][0]];}if(ch[u][1]){sumv[u]|=sumv[ch[u][1]];siz[u]+=siz[ch[u][1]];}
}
void reverse(int u){rev[u]^=1;swap(ch[u][0],ch[u][1]);
}
void maintain(int u,int c){tag[u]=c;sumv[u]=1<<c;if(u>n){val[u]=c;}
}
void downtag(int u){if(rev[u]){if(ch[u][0]){reverse(ch[u][0]);}if(ch[u][1]){reverse(ch[u][1]);}rev[u]=0;}if(tag[u]){if(ch[u][0]){maintain(ch[u][0],tag[u]);}if(ch[u][1]){maintain(ch[u][1],tag[u]);}tag[u]=0;}
}
void pushdown(int u){stk[stk[0]=1]=u;for(;!isroot(u);u=fa[u]){stk[++stk[0]]=fa[u];}while(stk[0]){downtag(stk[stk[0]--]);}
}
void rotate(int x){int y=fa[x],z=fa[y],md=which(x);if(!isroot(y)){ch[z][which(y)]=x;}fa[x]=z;ch[y][md]=ch[x][!md];fa[ch[y][md]]=y;ch[x][!md]=y;fa[y]=x;pushup(y);pushup(x);
}
void splay(int u){pushdown(u);while(!isroot(u)){if(!isroot(fa[u])){rotate(which(fa[u])==which(u)?fa[u]:u);}rotate(u);}
}
void access(int u){for(int v=0;u;v=u,u=fa[u]){splay(u);ch[u][1]=v;pushup(u);}
}
void makeroot(int u){access(u);splay(u);reverse(u);
}
void link(int u,int v){makeroot(u);fa[u]=v;
}
void cut(int u,int v){makeroot(u);access(v);splay(v);fa[u]=ch[v][0]=0;pushup(v);
}
/*bool judge(int u,int v){//用这个判断祖孙关系是错的if(u==v){return false;}access(v);splay(v);splay(u);return fa[v]==0;
}*/
bool judge(int u,int v){//暴力判断祖孙关系while(v){if(u==v){return false;}v=pa[v];}return true;
}
bool isconnect(int u,int v){if(u==v){return true;}makeroot(u);access(v);splay(v);return fa[u]!=0;
}
int main(){while(~scanf("%d%d",&n,&m)){memset(fa,0,sizeof(fa));memset(ch,0,sizeof(ch));memset(rev,0,sizeof(rev));memset(tag,0,sizeof(tag));memset(sumv,0,sizeof(sumv));memset(siz,0,sizeof(siz));memset(val,0,sizeof(val));memset(head,0,sizeof(head));rt[0]=cnt=0;for(int i=1;i<=n;i++){scanf("%d",&pa[i]);if(pa[i]){adde(pa[i],i+n);adde(i+n,pa[i]);adde(i,i+n);adde(i+n,i);}else{rt[++rt[0]]=i;}}for(int i=1;i<=n;i++){scanf("%d",&val[i+n]);sumv[i+n]=1<<val[i+n];siz[i]=siz[i+n]=1;}for(int i=1;i<=rt[0];i++){dfs(rt[i]);}for(int i=1;i<=m;i++){scanf("%d%d%d",&op,&u,&v);if(op==1){scanf("%d",&c);if(judge(u,v)){if(pa[u]){cut(pa[u],u+n);cut(u+n,u);}pa[u]=v;link(pa[u],u+n);link(u+n,u);splay(u+n);val[u+n]=c;pushup(u+n);}}else if(op==2){scanf("%d",&c);if(u!=v&&isconnect(u,v)){makeroot(u);access(v);splay(v);maintain(v,c);}}else{if(u==v||!isconnect(u,v)){puts("0 0");}else{makeroot(u);access(v);splay(v);ans=0;for(int j=1;j<=30;j++){if(sumv[v]&(1<<j)){ans++;}}printf("%d %d\n",(siz[v]-1)/2,ans);}}}}return 0;
}

转载于:https://www.cnblogs.com/2016gdgzoi471/p/9476908.html

【uva11994】Happy Painting!【LCT】相关推荐

  1. 【洛谷P4084】Barn Painting【树形DP】

    题目大意: 题目链接:https://www.luogu.org/problemnew/show/P4084 一棵nnn个节点的树上有kkk个点已被染色.求将这棵树染成三种颜色且相邻的节点颜色不同的方 ...

  2. SpringBoot 【IDEA热部署+浏览器禁用缓存】迅速提升效率

    SpringBoot微服务写页面,每次都需要重启才生效,使用[IDEA热部署+浏览器禁用缓存]迅速提升效率: 参考 https://blog.csdn.net/qq_27416233/article/ ...

  3. PHP安装扩展mcrypt以及相关依赖项 【PHP安装PECL扩展的方法】

    一:Mcrypt简介 Mcrypt是PHP的一个扩展,完成了常用加密算法的封装.其实该扩展是对mcrypt标准类库的封装,mcrypt完成了相当多的常用加密算法,如DES, TripleDES, Bl ...

  4. 【No.5 类型转换导致的错误】

    ==[注意]== 程序语言只是我们与计算机交流并让计算机实现我们创造性思想的工具,可以并鼓励深入掌握一门语言,但千万别沉迷于钻某种语言的牛角尖,一定要把握好二者间的度 本帖属不定时连载贴,以试卷的形式 ...

  5. 【我的Android进阶之旅】推荐一款能提升数十倍效率的Android应用开发助手

    一功能介绍 a调试相关 1布局边界 2布局更新 3强制GPU渲染 4GPU渲染 5指针位置 6严格模式 7不保留应用 8不锁定屏幕 9开发者选项 10系统设置 11语言设置 12USB调试 b UI相 ...

  6. 2021年Java面试题目最新总结【90%面试会踩的坑】

    学会java技术之后大家面临的最多的问题就是面试这关,求职面试java岗位是否能够成功是直接影响我们的工作机会的,所以对于Java程序员面试你准备好了吗?今天小编汇总了一下关于Java程序员面试,90 ...

  7. 【WEB API项目实战干货系列】- API登录与身份验证(三)

    上一篇: [WEB API项目实战干货系列]- 接口文档与在线测试(二) 这篇我们主要来介绍我们如何在API项目中完成API的登录及身份认证. 所以这篇会分为两部分, 登录API, API身份验证. ...

  8. zw版【转发·台湾nvp系列Delphi例程】HALCON Histogram

    zw版[转发·台湾nvp系列Delphi例程]HALCON Histogram unit Unit1; interface uses Windows, Messages, SysUtils, Vari ...

  9. 【从单体架构到分布式架构】(二)请求增多,单点变集群(1):负载均衡

    这是我的第 47 篇原创文章作者 l 会点代码的大叔(CodeDaShu) 上一个章节,我们搭建了一个最简单的单体服务项目,单体架构就是把所有的功能都放在一个工程项目中. 但是当访问量不断增加,我们只 ...

最新文章

  1. LOST OF DETAIL!!!的数学原理
  2. stm32 高级定时器产生PWM
  3. V8 Promise源码全面解读
  4. 【树链剖分】旅游(luogu 3976)
  5. 【HDU - 6441】Find Integer (费马大定理 + 奇偶数列法构造勾股定理)
  6. c语言variant是什么变量,介绍一些常用数据类型的使用。先定义一些常见类型变量借以.doc...
  7. 毕业一周年,工作一周年零七天
  8. 联发科发布天玑5G开放架构 采用该定制芯片终端7月上市
  9. php model get set方法,创建数据库对象之__set方法
  10. Linux、命令ps 各字段意思
  11. metasfresh 大型java开源制造业erp介绍
  12. Java实现文件下载Zip压缩
  13. win10无法装载iso文件_win10系统打开iso格式文件的四种方法
  14. 胡侃学习计算机--理论之外-From南大小百合
  15. 模拟数字接口及调制解调器
  16. 笔记本gtx1650最好用驱动_Intel EVO平台认证有啥用?只看真实性能 闭着眼买笔记本都不会错-Intel,EVO,笔记本,认证 ——快科技(驱动之家旗下媒体)-...
  17. FigDraw 21. SCI文章中绘图之三维散点图 (plot3D)
  18. 将阿拉伯数字转换为中文大写数字 —— pyhton实现
  19. 大盘向好、交付企稳,金科股份中报里的关键信号
  20. 一个简单的电子邮箱验证

热门文章

  1. 『Numpy』np.ravel()和np.flatten()
  2. JS实现的ajax和同源策略
  3. 1040. Longest Symmetric String (25)
  4. Ubuntu Server对OpenStack的支持
  5. C#分隔字符串时遭遇空值
  6. css选择器(css Selectors)的语法分析
  7. C#.NET禁止一个程序启动多个实例
  8. dram和nand哪个难生产_DRAM与NAND差别这么大,存储之争都争啥
  9. SpringCloud Config Server搭建
  10. leetcode算法题--包含min函数的栈