题目描述

Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作

输入

第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000

输出

每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值

样例输入

5 6
1 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5

样例输出

3
4
2
2
 
我们将连续相同颜色的一条链看成一条重链,可以发现修改操作其实就是$LCT$里的$access$操作。
那么每个节点到根的权值就是这个点到根路径上的重链数。
考虑用线段树维护出每个点到根的权值,每次修改时假设路径上$x->fa$的边是轻边,$fa$的重儿子是$son$,那么就将$son$子树中所有点的答案$+1$,$x$子树中所有点答案$-1$,然后将$x$变为$fa$的重儿子。在$access$时完成子树修改操作即可。
对于查询$x$到$y$的路径权值,就是$v[x]+v[y]-2v[lca]+1$。

  1. #include<set>
  2. #include<map>
  3. #include<queue>
  4. #include<stack>
  5. #include<cmath>
  6. #include<cstdio>
  7. #include<bitset>
  8. #include<vector>
  9. #include<cstring>
  10. #include<iostream>
  11. #include<algorithm>
  12. #define ll long long
  13. using namespace std;
  14. int c[100010][2];
  15. int fa[100010];
  16. int tag[400010];
  17. int f[100010][18];
  18. int dep[100010];
  19. int mx[400010];
  20. int dfn;
  21. int tot;
  22. int x,y;
  23. int n,m;
  24. int opt;
  25. int head[100010];
  26. int next[200010];
  27. int to[200010];
  28. int q[100010];
  29. int s[100010];
  30. int t[100010];
  31. void add(int x,int y)
  32. {
  33. next[++tot]=head[x];
  34. head[x]=tot;
  35. to[tot]=y;
  36. }
  37. void pushup(int rt)
  38. {
  39. mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
  40. }
  41. void pushdown(int rt)
  42. {
  43. if(tag[rt])
  44. {
  45. tag[rt<<1]+=tag[rt];
  46. tag[rt<<1|1]+=tag[rt];
  47. mx[rt<<1]+=tag[rt];
  48. mx[rt<<1|1]+=tag[rt];
  49. tag[rt]=0;
  50. }
  51. }
  52. void build(int rt,int l,int r)
  53. {
  54. if(l==r)
  55. {
  56. mx[rt]=dep[q[l]];
  57. return ;
  58. }
  59. int mid=(l+r)>>1;
  60. build(rt<<1,l,mid);
  61. build(rt<<1|1,mid+1,r);
  62. pushup(rt);
  63. }
  64. void change(int rt,int l,int r,int L,int R,int v)
  65. {
  66. if(L<=l&&r<=R)
  67. {
  68. tag[rt]+=v;
  69. mx[rt]+=v;
  70. return ;
  71. }
  72. pushdown(rt);
  73. int mid=(l+r)>>1;
  74. if(L<=mid)
  75. {
  76. change(rt<<1,l,mid,L,R,v);
  77. }
  78. if(R>mid)
  79. {
  80. change(rt<<1|1,mid+1,r,L,R,v);
  81. }
  82. pushup(rt);
  83. }
  84. int query(int rt,int l,int r,int L,int R)
  85. {
  86. if(L<=l&&r<=R)
  87. {
  88. return mx[rt];
  89. }
  90. pushdown(rt);
  91. int mid=(l+r)>>1;
  92. int res=0;
  93. if(L<=mid)
  94. {
  95. res=max(res,query(rt<<1,l,mid,L,R));
  96. }
  97. if(R>mid)
  98. {
  99. res=max(res,query(rt<<1|1,mid+1,r,L,R));
  100. }
  101. return res;
  102. }
  103. int ask(int rt,int l,int r,int k)
  104. {
  105. if(l==r)
  106. {
  107. return mx[rt];
  108. }
  109. pushdown(rt);
  110. int mid=(l+r)>>1;
  111. if(k<=mid)
  112. {
  113. return ask(rt<<1,l,mid,k);
  114. }
  115. else
  116. {
  117. return ask(rt<<1|1,mid+1,r,k);
  118. }
  119. }
  120. bool is_root(int rt)
  121. {
  122. return rt!=c[fa[rt]][0]&&rt!=c[fa[rt]][1];
  123. }
  124. bool get(int rt)
  125. {
  126. return rt==c[fa[rt]][1];
  127. }
  128. void rotate(int rt)
  129. {
  130. int x=fa[rt];
  131. int y=fa[x];
  132. int k=get(rt);
  133. if(!is_root(x))
  134. {
  135. c[y][get(x)]=rt;
  136. }
  137. c[x][k]=c[rt][k^1];
  138. fa[c[rt][k^1]]=x;
  139. c[rt][k^1]=x;
  140. fa[x]=rt;
  141. fa[rt]=y;
  142. }
  143. void splay(int rt)
  144. {
  145. for(int x;!is_root(rt);rotate(rt))
  146. {
  147. if(!is_root(x=fa[rt]))
  148. {
  149. rotate(get(x)==get(rt)?x:rt);
  150. }
  151. }
  152. }
  153. void link(int x,int y)
  154. {
  155. fa[x]=y;
  156. }
  157. int find(int rt)
  158. {
  159. while(c[rt][0])
  160. {
  161. rt=c[rt][0];
  162. }
  163. return rt;
  164. }
  165. void access(int rt)
  166. {
  167. for(int x=0;rt;x=rt,rt=fa[rt])
  168. {
  169. splay(rt);
  170. if(x)
  171. {
  172. int son=find(x);
  173. change(1,1,n,s[son],t[son],-1);
  174. }
  175. if(c[rt][1])
  176. {
  177. int son=find(c[rt][1]);
  178. change(1,1,n,s[son],t[son],1);
  179. }
  180. c[rt][1]=x;
  181. }
  182. }
  183. void dfs(int x)
  184. {
  185. s[x]=++dfn;
  186. q[dfn]=x;
  187. for(int i=1;i<=17;i++)
  188. {
  189. f[x][i]=f[f[x][i-1]][i-1];
  190. }
  191. for(int i=head[x];i;i=next[i])
  192. {
  193. if(to[i]!=f[x][0])
  194. {
  195. f[to[i]][0]=x;
  196. link(to[i],x);
  197. dep[to[i]]=dep[x]+1;
  198. dfs(to[i]);
  199. }
  200. }
  201. t[x]=dfn;
  202. }
  203. int lca(int x,int y)
  204. {
  205. if(dep[x]<dep[y])
  206. {
  207. swap(x,y);
  208. }
  209. int d=dep[x]-dep[y];
  210. for(int i=0;i<=17;i++)
  211. {
  212. if(d&(1<<i))
  213. {
  214. x=f[x][i];
  215. }
  216. }
  217. if(x==y)
  218. {
  219. return x;
  220. }
  221. for(int i=17;i>=0;i--)
  222. {
  223. if(f[x][i]!=f[y][i])
  224. {
  225. x=f[x][i];
  226. y=f[y][i];
  227. }
  228. }
  229. return f[x][0];
  230. }
  231. int main()
  232. {
  233. scanf("%d%d",&n,&m);
  234. for(int i=1;i<n;i++)
  235. {
  236. scanf("%d%d",&x,&y);
  237. add(x,y);
  238. add(y,x);
  239. }
  240. dep[1]=1;
  241. dfs(1);
  242. build(1,1,n);
  243. while(m--)
  244. {
  245. scanf("%d",&opt);
  246. if(opt==1)
  247. {
  248. scanf("%d",&x);
  249. access(x);
  250. }
  251. else if(opt==2)
  252. {
  253. scanf("%d%d",&x,&y);
  254. int anc=lca(x,y);
  255. int ans=ask(1,1,n,s[x])+ask(1,1,n,s[y])-2*ask(1,1,n,s[anc])+1;
  256. printf("%d\n",ans);
  257. }
  258. else
  259. {
  260. scanf("%d",&x);
  261. printf("%d\n",query(1,1,n,s[x],t[x]));
  262. }
  263. }
  264. }

BZOJ4817[Sdoi2017]树点涂色——LCT+线段树的更多相关文章

  1. 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树

    [BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...

  2. 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]

    树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...

  3. [Sdoi2017]树点涂色 [lct 线段树]

    [Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...

  4. [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]

    题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...

  5. bzoj4817 & loj2001 [Sdoi2017]树点涂色 LCT + 线段树

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4817 https://loj.ac/problem/2001 题解 可以发现这个题就是 bzo ...

  6. BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)

    题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...

  7. 【bzoj4817】树点涂色 LCT+线段树+dfs序

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  8. BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树

    同BZOJ3779. SDOI出原题,还是弱化版的. 吃枣药丸 #include <map> #include <cmath> #include <queue> # ...

  9. BZOJ 4817: [Sdoi2017]树点涂色(lct+线段树)

    传送门 解题思路 跟重组病毒这道题很像.只是有了一个询问\(2\)的操作,然后询问\(2\)的答案其实就是\(val[x]+val[y]-2*val[lca(x,y)]+1\)(画图理解).剩下的操作 ...

随机推荐

  1. 荣耀MagicBook黑苹果(i7)High Sierra 10.13.6

    这里有大佬维护的新版本EFI,对应10.14.4:https://github.com/hjmmc/Honor-Magicbook ---------------------------------- ...

  2. 【20190405】JavaScript-整理一些常用正则式

    匹配中文字符: let reg=/([\u4E00-\u9FFF]+)/; //\u代表Unicode编码 匹配电话号码: let reg=/^1[34578]\d{9}$/; 给每三位数字添加一个逗 ...

  3. 驰骋工作流引擎JFlow与activiti的对比 -总结

    共同点: 1. 嵌入式的工作流引擎,降低集群复杂性. 2. 严格而灵活的流程版本控制 3. 支持多种数据库 4. 支持多种流程设计模式 5. 成熟度高的开源工作流,具有可靠的稳定性和性能. 区别: 1 ...

  4. 在IIS上部署你的ASP.NET Core 2.1项目

    1.在控制面板→程序→启用或关闭Windows功能→勾选Internet Information Services以及Web管理工具下的IIS管理控制台 2.IIS 安装AspNetCoreModul ...

  5. Arcgis瓦片--数据获取

    Arcgis的二维地图瓦片有两种获取方式 1.在Arcmap中对配置好的地图进行切图,生成对应瓦片 2.使用第三方的地图下载器,直接下载,导出成arcgis瓦片格式即可使用. 备注:这里主要介绍第二种 ...

  6. 企业信息化-Excel快速生成系统

    企业信息化,主要是指对企业生产运营过程所形成的信息数字化,最终形成了数字资产.大型企业为了节约成本,提高协同工作效率,都会定制ERP.办公OA.流程审批等系统做信息化支撑.但是中小企业精力投入到生成中 ...

  7. win快捷键

    ******************键盘快捷键大全******************  一.常见用法: F1 显示当前程序或者windows的帮助内容. F2 当你选中一个文件的话,这意味着“重命名 ...

  8. huffman树即Huffma编码的实现

    自己写的Huffman树生成与Huffman编码实现 (实现了核心功能 ,打出了每个字符的huffman编码 其他的懒得实现了,有兴趣的朋友可以自己在我的基础增加功能 ) /* 原创文章 转载请附上原 ...

  9. MS SQL自定义函数判断是否正整数

    可以写一个函数: 主要是使用正则来判断.另外输入字符是空的话,使用"-"来替换. CREATE FUNCTION [dbo].[svf_NonNegativeInteger] ( ...

  10. MySQL常用数值函数

    数值函数: 用来处理很多数值方面的运算,使用数值函数,可以免去很多繁杂的判断求值的过程,能够大大提高用户的工作效率. 1.ABS(x):返回 x 的绝对值 mysql> select abs(- ...