本来只是想练练LCT,没想到是个线段树

对于操作1:诶新的颜色?这不是access吗?

也就是说,我们用一棵splay来表示一种颜色

操作2直接在LCT上乱搞……

不对啊,操作3要查子树

诶好像是静态的

那可以考虑线段树维护dfs序

现在要考虑怎么维护权值

我们发现开始的时候权值就是节点的深度

而在且只在access的时候会改变权值

试试魔改access?

原来:

  1. for (int y=0;x;y=x,x=fa[x])
  2. {
  3. splay(x);
  4. ch[x][1]=y;
  5. update(x);
  6. }

那么主要就是\(ch[x][1]=y\)

实际上这句话包含两个操作:清除\(ch[x][1]\),把\(y\)接到\(x\)的右儿子

清除\(ch[x][1]\),相当于把原来的重边断开

我们只考虑当前这个点改了之后的影响

注意既然他们是重边连起来的,他们原来一定是同色的

而改了之后他们就不同了,所以y的子树权值都会增加1

并且他也不会和这条到根路径上任何一个出现过的颜色相同

同样,把\(y\)接到\(x\)的右儿子,意味着x和y同色了,而原来是不同的,所以y的子树权值都会减少1

线段树维护一下就好

操作2直接单点查询,类似树上前缀和就可以了

于是乎,LCT40多行……

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cctype>
  5. #define MAXN 1000005
  6. #define MAXM 2000005
  7. using namespace std;
  8. inline int read()
  9. {
  10. int ans=0;
  11. char c=getchar();
  12. while (!isdigit(c)) c=getchar();
  13. while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
  14. return ans;
  15. }
  16. struct edge
  17. {
  18. int u,v;
  19. }e[MAXM];
  20. int head[MAXN],nxt[MAXM],cnt;
  21. void addnode(int u,int v)
  22. {
  23. e[++cnt]=(edge){u,v};
  24. nxt[cnt]=head[u];
  25. head[u]=cnt;
  26. }
  27. int dep[MAXN],fa[MAXN],up[MAXN][20];
  28. int dfn[MAXN],pos[MAXN],tim,end[MAXN];
  29. void dfs(int u)
  30. {
  31. dfn[u]=++tim;
  32. pos[tim]=u;
  33. for (int i=1;i<20;i++)
  34. up[u][i]=up[up[u][i-1]][i-1];
  35. for (int i=head[u];i;i=nxt[i])
  36. if (!dep[e[i].v])
  37. {
  38. dep[e[i].v]=dep[u]+1;
  39. up[e[i].v][0]=u;
  40. fa[e[i].v]=u;
  41. dfs(e[i].v);
  42. }
  43. end[u]=tim;
  44. }
  45. int lca(int x,int y)
  46. {
  47. if (dep[x]<dep[y]) swap(x,y);
  48. int t=dep[x]-dep[y];
  49. for (int i=0;(1<<i)<=t;i++)
  50. if (t&(1<<i))
  51. x=up[x][i];
  52. if (x==y) return x;
  53. for (int i=19;i>=0;i--)
  54. if (up[x][i]!=up[y][i])
  55. x=up[x][i],y=up[y][i];
  56. return up[x][0];
  57. }
  58. namespace SGT
  59. {
  60. #define lc p<<1
  61. #define rc p<<1|1
  62. struct SegmentTree
  63. {
  64. int l,r;
  65. int lazy;
  66. int mx;
  67. }t[MAXN<<2];
  68. void pushup(int p){t[p].mx=max(t[lc].mx,t[rc].mx);}
  69. void pushlazy(int p,int v){t[p].mx+=v,t[p].lazy+=v;}
  70. void pushdown(int p)
  71. {
  72. if (t[p].lazy)
  73. {
  74. pushlazy(lc,t[p].lazy);
  75. pushlazy(rc,t[p].lazy);
  76. t[p].lazy=0;
  77. }
  78. }
  79. void build(int p,int l,int r)
  80. {
  81. t[p].l=l,t[p].r=r;
  82. if (l==r){t[p].mx=dep[pos[l]];return;}
  83. int mid=(l+r)>>1;
  84. build(lc,l,mid),build(rc,mid+1,r);
  85. pushup(p);
  86. }
  87. void modify(int p,int l,int r,int v)
  88. {
  89. if (l<=t[p].l&&t[p].r<=r) return pushlazy(p,v);
  90. if (r<t[p].l||t[p].r<l) return;
  91. pushdown(p);
  92. if (l<=t[lc].r) modify(lc,l,r,v);
  93. if (t[rc].l<=r) modify(rc,l,r,v);
  94. pushup(p);
  95. }
  96. int querymax(int p,int l,int r)
  97. {
  98. pushdown(p);
  99. if (l<=t[p].l&&t[p].r<=r) return t[p].mx;
  100. if (r<t[p].l||t[p].r<l) return 0;
  101. int ans=0;
  102. if (l<=t[lc].r) ans=max(ans,querymax(lc,l,r));
  103. if (t[rc].l<=r) ans=max(ans,querymax(rc,l,r));
  104. return ans;
  105. }
  106. int query(int p,int k)
  107. {
  108. pushdown(p);
  109. if (t[p].l==t[p].r) return t[p].mx;
  110. if (k<=t[lc].r) return query(lc,k);
  111. else return query(rc,k);
  112. }
  113. }
  114. using namespace SGT;
  115. namespace Splay
  116. {
  117. int ch[MAXN][2];
  118. bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
  119. int get(int x){return ch[fa[x]][1]==x;}
  120. void rotate(int x)
  121. {
  122. int y=fa[x],z=fa[y];
  123. int l=get(x),r=l^1;
  124. int w=ch[x][r];
  125. if (!isroot(y)) ch[z][get(y)]=x;
  126. ch[x][r]=y,ch[y][l]=w;
  127. if (w) fa[w]=y;
  128. fa[y]=x,fa[x]=z;
  129. }
  130. void splay(int x)
  131. {
  132. while (!isroot(x))
  133. {
  134. int y=fa[x];
  135. if (!isroot(y))
  136. {
  137. if (get(x)==get(y)) rotate(y);
  138. else rotate(x);
  139. }
  140. rotate(x);
  141. }
  142. }
  143. }
  144. using namespace Splay;
  145. namespace LCT
  146. {
  147. int findroot(int x){while (ch[x][0]) x=ch[x][0];return x;}
  148. void access(int x)
  149. {
  150. int w;
  151. for (int y=0;x;y=x,x=fa[x])
  152. {
  153. splay(x);
  154. if (ch[x][1]){w=findroot(ch[x][1]),modify(1,dfn[w],end[w],1);}
  155. if (ch[x][1]=y){w=findroot(y),modify(1,dfn[w],end[w],-1);}
  156. }
  157. }
  158. }
  159. using namespace LCT;
  160. int main()
  161. {
  162. int n,m;
  163. n=read(),m=read();
  164. for (int i=1;i<n;i++)
  165. {
  166. int u,v;
  167. u=read(),v=read();
  168. addnode(u,v),addnode(v,u);
  169. }
  170. dep[1]=1;
  171. dfs(1);
  172. build(1,1,n);
  173. while (m--)
  174. {
  175. int op,x,y,l;
  176. op=read(),x=read();
  177. int ans;
  178. switch(op)
  179. {
  180. case 1:access(x);break;
  181. case 2:
  182. y=read();
  183. l=lca(x,y);
  184. ans=query(1,dfn[x]);
  185. ans+=query(1,dfn[y]);
  186. ans-=(query(1,dfn[l])<<1);
  187. printf("%d\n",ans+1);
  188. break;
  189. case 3:
  190. printf("%d\n",querymax(1,dfn[x],end[x]));
  191. }
  192. }
  193. return 0;
  194. }

【SDOI2017】树点染色【线段树+LCT】的更多相关文章

  1. codevs 1191 树轴染色 线段树区间定值,求和

    codevs 1191 树轴染色 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.codevs.cn/problem/1191/ Des ...

  2. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  3. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

  4. B20J_2243_[SDOI2011]染色_树链剖分+线段树

    B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...

  5. 2243: [SDOI2011]染色 树链剖分+线段树染色

    给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...

  6. BZOJ - 2243 染色 (树链剖分+线段树+区间合并)

    题目链接 线段树维护区间连续段个数即可.设lc为区间左端点颜色,rc为区间右端点颜色,则合并两区间的时候,如果左区间右端点和右区间左端点颜色相同,则连续段个数-1. 在树链上的区间合并可以定义一个结构 ...

  7. BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

    题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...

  8. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  9. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

  10. [luogu3676] 小清新数据结构题 [树链剖分+线段树]

    题面 传送门 思路 本来以为这道题可以LCT维护子树信息直接做的,后来发现这样会因为splay形态改变影响子树权值平方和,是splay本身的局限性导致的 所以只能另辟蹊径 首先,我们考虑询问点都在1的 ...

随机推荐

  1. 【BZOJ】2565: 最长双回文串

    [题意]给定小写字母字符串s,求最长的 [ 可以分成左右两个回文串的 ] 子串,n<=10^5. [算法]回文树 [题解]对于每个字符x,处理出以x结尾的最长回文串,以x开头的最长回文串,然后枚 ...

  2. 通用标签、属性(body属性、路径、格式控制)

    通用标签.属性 一.body属性 1.bgcolor属性:网页背景颜色 2.text属性:规定文档中所有文本的颜色. 3.background属性:规定文档的背景图像. 二.路径 1.绝对路径: 从根 ...

  3. jq消除网页滚动条

    网页有些时候需要能滚动的效果,但是不想要滚动条,我就遇到了这样的需求.自己用jq写了一个垂直滚动条. 纯css也可以实现 .box::-webkit-scrollbar{display:none} 但 ...

  4. css3同心圆闪烁扩散效果

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  5. Windows降权

    使用invoke-tokenmanipulation进行降权 枚举所有令牌 PS C:\Users\SMC> Get-ExecutionPolicy Restricted PS C:\Users ...

  6. 【日期控件】JQueryUI的datepicker日期控件

    在输入日期的时候我们经常需要日期控件,jQueryUI的datapicker就是一个很好的日期控件. 1.简单的datepicker控件 目录结构:(要将images图片放到css目录下面)

  7. python基础===15条变量&方法命名的最佳实践

    不同的代码段采用不同的命名长度.通常来说,循环计数器(loop counters)采用1位的单字符来命名,循环判断变量(condition/loop variables)采用1个单词来命名,方法采用1 ...

  8. C# Selenium with PhantomJSDriver get image width and height (获取图片的长和高)

    //get image width and height var image=driver.FindElement(By.ClassName("it-Header_authorImage&q ...

  9. C#开发微信公众平台开发-微信海报介绍和开发流程

    “让客户发展客户”,微信海报才是微信公众平台最高明的吸粉手段,海报上有粉丝的专属二维码,有粉丝的头像及商户宣传的广告等.新粉丝扫描这个专属二维码会关注公众号,同时分享海报的粉丝会增加积分换取礼品或者优 ...

  10. AJP与HTTP比较和分析

    系统环境: OS:Ubuntu 10.10 (2G) Servlet Container:tomcat-tomcat-7.0.23  (最大内存:default 256M  maxThreads:50 ...