link

你谷的第一篇题解没用写LCT,然后没观察懂,但是自己YY了一种不用LCT的做法

我们考虑对于每个点,维护一个fa,代表以1为根时候这个点的父亲

再维护一个bel,由于一个颜色相同的段一定是一个深度递增的链,这个代表颜色段的链顶

再维护一个ans,就是ans

那么第二个操作就是ans单点查询,第三个就是ans区间最大值

第一个操作,我们树剖把它变成了log条重链,在重链上的点的bel和ans可以区间修改

但是重链上每个点的儿子就说gg了

这些儿子的子树减去的是他们的各自bel的fa的点权,然后在加上一个1

所以说每个点还要维护一个preferred child,显然很难写(但是应该是可以实现的),还是写动态树吧

动态树其实是动态树的阉割版,我们用一个splay维护树中颜色相同的点,显然这种点一定是一段深度递增的链,于是你会发现只需要钦定1为根,操作1就是access

然后我们可以维护每个点操作3的ans,再搞个dfn,操作3就可以用线段树维护,然而每个点的答案就相当于动态树上这个点到根节点上虚边的个数+1,我们可以搞个线段树维护,在动态树access虚实变化时候搞个区间加法即可

然后你会发现对于操作2的x,y答案就是ans[x] + ans[y] - 2 * ans[lc] + 1,所以说我们还需要支持一个lca操作,写个树剖或者倍增就行了,我为了凑齐全家桶就写了个树剖

注意树剖的fa和lct的fa一开始是一个fa,lct的fa是动态维护的,树剖的fa是静态的,要开两个数组并且别弄混了,调了好长时间...

access过程中由于变换的是深度恰好为depth[x]+1的点,所以就要对x寻找后继,就是x的右儿子不停往左跳。。。

时间复杂度Nlog^2N

  1. #include <cstdio>
  2. #include <vector>
  3. using namespace std;
  4. //区间加法,区间取max
  5. int fa[100010], dfn[100010], depth[100010], weight[100010], wson[100010], top[100010];
  6. int tree[400010], lazy[400010], fuck[100010], ch[100010][2], fat[100010], tot, n, m;
  7. vector<int> out[100010];
  8. void init(int x, int cl, int cr)
  9. {
  10. if (cl == cr)
  11. {
  12. tree[x] = fuck[cl];
  13. }
  14. else
  15. {
  16. int mid = (cl + cr) / 2;
  17. init(x * 2, cl, mid), init(x * 2 + 1, mid + 1, cr);
  18. tree[x] = max(tree[x * 2], tree[x * 2 + 1]);
  19. }
  20. }
  21. void pushdown(int x)
  22. {
  23. tree[x * 2] += lazy[x], tree[x * 2 + 1] += lazy[x];
  24. lazy[x * 2] += lazy[x], lazy[x * 2 + 1] += lazy[x];
  25. lazy[x] = 0;
  26. }
  27. void chenge(int x, int cl, int cr, int L, int R, int val)
  28. {
  29. if (cr < L || R < cl) return;
  30. if (L <= cl && cr <= R) { tree[x] += val, lazy[x] += val; return; }
  31. pushdown(x);
  32. int mid = (cl + cr) / 2;
  33. chenge(x * 2, cl, mid, L, R, val);
  34. chenge(x * 2 + 1, mid + 1, cr, L, R, val);
  35. tree[x] = max(tree[x * 2], tree[x * 2 + 1]);
  36. }
  37. int query(int x, int cl, int cr, int L, int R)
  38. {
  39. if (cr < L || R < cl) return 0;
  40. if (L <= cl && cr <= R) return tree[x];
  41. pushdown(x);
  42. int mid = (cl + cr) / 2;
  43. return max(query(x * 2, cl, mid, L, R), query(x * 2 + 1, mid + 1, cr, L, R));
  44. }
  45. void dfs1(int x)
  46. {
  47. weight[x] = 1, wson[x] = -1;
  48. for (int i : out[x]) if (fa[x] != i)
  49. {
  50. fa[i] = fat[i] = x, depth[i] = depth[x] + 1;
  51. dfs1(i), weight[x] += weight[i];
  52. if (wson[x] == -1 || weight[wson[x]] < weight[i]) wson[x] = i;
  53. }
  54. }
  55. void dfs2(int x, int topf)
  56. {
  57. dfn[x] = ++tot, top[x] = topf, fuck[dfn[x]] = depth[x] + 1;
  58. if (wson[x] == -1) return;
  59. dfs2(wson[x], topf);
  60. for (int i : out[x]) if (fa[x] != i && wson[x] != i) dfs2(i, i);
  61. }
  62. int lca(int x, int y)
  63. {
  64. while (top[x] != top[y])
  65. {
  66. if (depth[top[x]] < depth[top[y]]) swap(x, y);
  67. x = fa[top[x]];
  68. }
  69. if (depth[x] > depth[y]) swap(x, y);
  70. return x;
  71. }
  72. bool nroot(int x) { return ch[fat[x]][0] == x || ch[fat[x]][1] == x; }
  73. void rotate(int x)
  74. {
  75. int y = fat[x], z = fat[y], k = ch[y][1] == x, w = ch[x][k ^ 1];
  76. if (nroot(y)) { ch[z][ch[z][1] == y] = x; } ch[x][k ^ 1] = y, ch[y][k] = w;
  77. if (w) { fat[w] = y; } fat[y] = x; fat[x] = z;
  78. }
  79. void splay(int x)
  80. {
  81. while (nroot(x))
  82. {
  83. int y = fat[x], z = fat[y];
  84. if (nroot(y)) rotate((ch[y][1] == x) ^ (ch[z][1] == y) ? x : y);
  85. rotate(x);
  86. }
  87. }
  88. int findrt(int x)
  89. {
  90. while (ch[x][0]) x = ch[x][0];
  91. return x;
  92. }
  93. void access(int x)
  94. {
  95. for (int y = 0; x > 0; x = fat[y = x])
  96. {
  97. splay(x);
  98. if (ch[x][1])
  99. {
  100. int p = findrt(ch[x][1]);
  101. chenge(1, 1, n, dfn[p], dfn[p] + weight[p] - 1, 1);
  102. }
  103. ch[x][1] = y;
  104. if (y)
  105. {
  106. int p = findrt(y);
  107. chenge(1, 1, n, dfn[p], dfn[p] + weight[p] - 1, -1);
  108. }
  109. }
  110. }
  111. int main()
  112. {
  113. scanf("%d%d", &n, &m);
  114. for (int x, y, i = 1; i < n; i++) scanf("%d%d", &x, &y), out[x].push_back(y), out[y].push_back(x);
  115. dfs1(1), dfs2(1, 1); init(1, 1, n);
  116. for (int opd, x, y, i = 1; i <= m; i++)
  117. {
  118. scanf("%d%d", &opd, &x);
  119. if (opd == 1) access(x);
  120. if (opd == 2)
  121. {
  122. scanf("%d", &y);
  123. int lc = lca(x, y);
  124. printf("%d\n", query(1, 1, n, dfn[x], dfn[x]) + query(1, 1, n, dfn[y], dfn[y]) - 2 * query(1, 1, n, dfn[lc], dfn[lc]) + 1);
  125. }
  126. if (opd == 3) printf("%d\n", query(1, 1, n, dfn[x], dfn[x] + weight[x] - 1));
  127. }
  128. return 0;
  129. }

luogu3703 [SDOI2017]树点涂色(线段树+树链剖分+动态树)的更多相关文章

  1. URAL1553 Caves and Tunnels 树链剖分 动态树

    URAL1553 维护一棵树,随时修改某个节点的权值,询问(x,y)路径上权值最大的点. 树是静态的,不过套动态树也能过,时限卡的严就得上树链剖分了. 还是那句话 splay的核心是splay(x) ...

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

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

  3. [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 692  Solved: 408[Submit][Status ...

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

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

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

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

  6. 「SDOI2017」树点涂色 解题报告

    「SDOI2017」树点涂色 我sb的不行了 其实一开始有一个类似动态dp的想法 每个点维护到lct树上到最浅点的颜色段数,然后维护一个\(mx_{0,1}\)也就是是否用虚儿子的最大颜色 用个set ...

  7. P3703 [SDOI2017]树点涂色

    P3703 [SDOI2017]树点涂色 链接 分析: 首先对于询问,感觉是线段树维护dfs序,每个点记录到根的颜色个数.第二问差分,第三问区间取max. 那么考虑修改,每次将一个点的颜色变成和父节点 ...

  8. [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 629  Solved: 371[Submit][Status ...

  9. 【LG3703】[SDOI2017]树点涂色

    [LG3703][SDOI2017]树点涂色 题面 洛谷 题解 更博辣,更博辣!!! 猪年的第一篇博客 一次只能染根到\(x\),且染的颜色未出现过 这句话是我们解题的关键. 设\(x\)到根的颜色数 ...

随机推荐

  1. pl/sql Command Window

    由于工作需要,最近需要执行sql脚本,之前一直在用执行按钮操作,但最近公司制定了一套标准,其中就有执行sql脚本规范: 以前执行存存储过程: 现在修改存储过程如下: 第一步,打开对应窗口: 第二步,输 ...

  2. Coins and Queries(codeforce 1003D)

    Polycarp has nn coins, the value of the i-th coin is aiai . It is guaranteed that all the values are ...

  3. latex中如何引用公式

    在使用latex编辑文章时,经常会需要引用公式.图表等等. 如果我们人为地对这些公式.图表进行编号1-2-3-4,然后在文章中使用Eq(1)-Eq(2)-Eq(3)-Eq(4)去引用这些公式,固然是可 ...

  4. java基础知识(一)之数据类型和运算符

    1.标识符:JAVA里面我们可以为之命名的就是标识符,如变量.方法.类等. 但是标识符只能包含字母.数字.下划线(_)和美元符号($),并且只能以字母.下划线和美元符号开头不能以数字开头.2.变量:在 ...

  5. FZU2282 Wand

    题意 n个数字,要求至少k个数字位置不变,其余进行错排的方案数 分析 错排公式: D(n)=(n-1)[D(n-2)+D(n-1)]  如果n个数字,i个数字位置不变,其余进行错排的的方案数是C(n, ...

  6. 【HDU3394】Railway

    [题目描述] 有一个公园有n个景点,公园的管理员准备修建m条道路,并且安排一些形成回路的参观路线.如果一条道路被多条道路公用,那么这条路是冲突的:如果一条道路没在任何一个回路内,那么这条路是不冲突的 ...

  7. CMake 自定义编译选项

    自定义编译选项 CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案. 例如,可以将 MathFunctions 库设为一个可选库,如果该选项为 ON ,就使用该库定义 ...

  8. jdbc中Statement和PreparedStatement有什么区别?哪个性能更好?

    Statement和PreparedStatement的功能主要是对sql语句的执行 区别 (1)Statement每执行一条sql语句就需要生成一条执行计划,执行100条就需要100条执行计划Pre ...

  9. 特征选择Boruta

    A good feature subset is one that: contains features highly correlated with (predictive of) the clas ...

  10. .net对Cookie的简单操作

    1 声明:HttpCookie MyCookie= new HttpCookie("test"); 2增加:MyCookie.Values.Add("key1" ...