正题

题目链接:https://www.luogu.com.cn/problem/P3703


题目大意

\(n\)个点的一棵树开始所有点有不同的颜色,\(m\)次操作

  1. 将根节点到\(x\)节点的路径上染上一种新的颜色
  2. 询问一条路径的不同颜色个数
  3. 询问一个节点的子树中的一个\(x\)使得\(x\)到根节点的颜色最多。

解题思路

操作\(1\)和\(LCT\)的\(access\)操作很相似。相同颜色之间就是实边,不同颜色之间就是虚边。

操作\(2\)就是之间\(p_x+p_y-2p_{LCA}+1\)就好了,但是考虑到操作\(3\),所以维护一个\(dfn\)序和线段树就可以查询子树最大值了。

之后维护一个\(LCT\),在\(access\)操作切换虚实边的时候修改一下线段树就好了,并且需要注意我们不能直接拿\(Splay\)的根的子树,要找到实际的树中的根,所以\(Splay\)一直往左就好了。

好像还有树链剖分的做法,线段树查询的时候维护一下末尾颜色好像就可以了,这里不多讲(我也不会)

时间复杂度\(O(n\log^2 n)\)


code

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N=1e5+10;
  6. struct node{
  7. int to,next;
  8. }a[N<<1];
  9. int n,m,cnt,tot,ls[N],rfn[N],ed[N],fa[N];
  10. int dep[N],son[N],siz[N],top[N];
  11. struct SegTree{
  12. int w[N<<2],lazy[N<<2];
  13. void Downdata(int x){
  14. if(!lazy[x])return;
  15. w[x*2]+=lazy[x];lazy[x*2]+=lazy[x];
  16. w[x*2+1]+=lazy[x];lazy[x*2+1]+=lazy[x];
  17. lazy[x]=0;return;
  18. }
  19. void Change(int x,int L,int R,int l,int r,int val){
  20. if(L==l&&R==r){w[x]+=val;lazy[x]+=val;return;}
  21. int mid=(L+R)>>1;Downdata(x);
  22. if(r<=mid)Change(x*2,L,mid,l,r,val);
  23. else if(l>mid)Change(x*2+1,mid+1,R,l,r,val);
  24. else Change(x*2,L,mid,l,mid,val),Change(x*2+1,mid+1,R,mid+1,r,val);
  25. w[x]=max(w[x*2],w[x*2+1]);return;
  26. }
  27. int Ask(int x,int L,int R,int l,int r){
  28. if(L==l&&R==r)return w[x];
  29. int mid=(L+R)>>1;Downdata(x);
  30. if(r<=mid)return Ask(x*2,L,mid,l,r);
  31. if(l>mid)return Ask(x*2+1,mid+1,R,l,r);
  32. return max(Ask(x*2,L,mid,l,mid),Ask(x*2+1,mid+1,R,mid+1,r));
  33. }
  34. }Tr;
  35. struct LinkCutTree{
  36. int t[N][2],fa[N];
  37. bool Nroot(int x)
  38. {return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}
  39. bool Direct(int x)
  40. {return t[fa[x]][1]==x;}
  41. void Rotate(int x){
  42. int y=fa[x],z=fa[y];
  43. int xs=Direct(x),ys=Direct(y);
  44. int w=t[x][xs^1];
  45. if(Nroot(y))t[z][ys]=x;
  46. t[x][xs^1]=y;t[y][xs]=w;
  47. if(w)fa[w]=y;fa[y]=x;fa[x]=z;
  48. return;
  49. }
  50. void Splay(int x){
  51. while(Nroot(x)){
  52. int y=fa[x];
  53. if(!Nroot(y))Rotate(x);
  54. else if(Direct(x)==Direct(y))
  55. Rotate(y),Rotate(x);
  56. else Rotate(x),Rotate(x);
  57. }
  58. return;
  59. }
  60. int FindRoot(int x){
  61. while(t[x][0])x=t[x][0];
  62. return x;
  63. }
  64. void Access(int x){
  65. for(int y=0;x;y=x,x=fa[x]){
  66. Splay(x);int z=t[x][1];
  67. if(z)z=FindRoot(z),Tr.Change(1,1,n,rfn[z],ed[z],1);
  68. if(y)z=FindRoot(y),Tr.Change(1,1,n,rfn[z],ed[z],-1);
  69. t[x][1]=y;
  70. }
  71. return;
  72. }
  73. }T;
  74. void addl(int x,int y){
  75. a[++tot].to=y;
  76. a[tot].next=ls[x];
  77. ls[x]=tot;return;
  78. }
  79. void dfs1(int x){
  80. siz[x]=1;rfn[x]=++cnt;
  81. dep[x]=dep[fa[x]]+1;T.fa[x]=fa[x];
  82. Tr.Change(1,1,n,cnt,cnt,dep[x]);
  83. for(int i=ls[x];i;i=a[i].next){
  84. int y=a[i].to;
  85. if(y==fa[x])continue;
  86. fa[y]=x;dfs1(y);siz[x]+=siz[y];
  87. if(siz[y]>siz[son[x]])son[x]=y;
  88. }
  89. ed[x]=cnt;
  90. }
  91. void dfs2(int x){
  92. if(son[x]){
  93. top[son[x]]=top[x];
  94. dfs2(son[x]);
  95. }
  96. for(int i=ls[x];i;i=a[i].next){
  97. int y=a[i].to;
  98. if(y==fa[x]||y==son[x])continue;
  99. top[y]=y;dfs2(y);
  100. }
  101. return;
  102. }
  103. int LCA(int x,int y){
  104. while(top[x]!=top[y]){
  105. if(dep[top[x]]<dep[top[y]])
  106. swap(x,y);
  107. x=fa[top[x]];
  108. }
  109. return dep[x]<dep[y]?x:y;
  110. }
  111. int main()
  112. {
  113. // freopen("paint1.in","r",stdin);
  114. scanf("%d%d",&n,&m);
  115. for(int i=1;i<n;i++){
  116. int x,y;
  117. scanf("%d%d",&x,&y);
  118. addl(x,y);addl(y,x);
  119. }
  120. dfs1(1);dfs2(1);
  121. while(m--){
  122. int op,x,y;
  123. scanf("%d%d",&op,&x);
  124. if(op==1)T.Access(x);
  125. else if(op==2){
  126. scanf("%d",&y);
  127. int lca=LCA(x,y);
  128. int p1=Tr.Ask(1,1,n,rfn[x],rfn[x]);
  129. int p2=Tr.Ask(1,1,n,rfn[y],rfn[y]);
  130. int p3=Tr.Ask(1,1,n,rfn[lca],rfn[lca]);
  131. printf("%d\n",p1+p2-p3*2+1);
  132. }
  133. else printf("%d\n",Tr.Ask(1,1,n,rfn[x],ed[x]));
  134. }
  135. return 0;
  136. }

P3703-[SDOI2017]树点涂色【LCT,线段树】的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. BZOJ4817[Sdoi2017]树点涂色——LCT+线段树

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

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

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

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

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

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

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

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

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

随机推荐

  1. 深层剖析鸿蒙轻内核M核的动态内存如何支持多段非连续性内存

    摘要:鸿蒙轻内核M核新增支持了多段非连续性内存区域,把多个非连续性内存逻辑上合一,用户不感知底层的不同内存块. 本文分享自华为云社区<鸿蒙轻内核M核源码分析系列九 动态内存Dynamic Mem ...

  2. 浅看spa单页应用路由

    路由观察浏览器的URL的变更.当URL 变更时,路由会解析它并生成一个新的路由实例. 一个基本的路由是这样的: class Router { private _defaultController: s ...

  3. vue+cesium初探(一) 加载cesium

    参考文章1:https://www.cnblogs.com/laixiangran/p/4984522.html 参考文章2:https://blog.csdn.net/weixin_41940497 ...

  4. 2018秋招C/C++面试题总结

    一.C和C++的区别是什么? C是面向过程的语言,C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛.C中函数不能进行重载,C++函数可以重载C++在C的基础上增添类,C是一个结构化语言,它 ...

  5. 解析一个HTML字符串

    存在问题 来自用户输入,一个文件或一个网站的HTML字符串,你可能需要对它进行解析并取其内容,或校验其格式是否完整,或想修改它.怎么办?jsonu能够帮你轻松解决这些问题 解决方法 使用静态Jsoup ...

  6. qt 中的画图

  7. 三:ServletContext对象

    一.ServletContext对象 1.什么是ServletContext对象 ServletContext代表是一个web应用的环境(上下文)对象,ServletContext对象 内部封装是该w ...

  8. 关于oracle样例数据库emp、dept、salgrade的mysql脚本复杂查询分析

    大家可以自行网上找资源(网上资源比较多,不建议下载我的),也可以在我这里下载: 1.取得每个部门最高薪水的人员名称:正确   一共有4个单位,要进行左外连接 其中一个单位没得员工 SELECT dep ...

  9. 理解Java中对象基础Object类

    一.Object简述 源码注释:Object类是所有类层级关系的Root节点,作为所有类的超类,包括数组也实现了该类的方法,注意这里说的很明确,指类层面. 所以在Java中有一句常说的话,一切皆对象, ...

  10. ubuntu中用update-alternatives进行软件多版本设置、切换,以python配置为例

    以Python2.7和Python3.5设置为例: 在系统中添加Python2.7.Python3.5的选项,默认为Python3.5 sudo update-alternatives --insta ...