Brief Description

给定一个森林,您需要支持两种操作:

  1. 链接两个节点。
  2. 断开两个节点之间的链接。

Algorithm Design

对于树上的操作,我们现在已经有了树链剖分可以处理这些问题。然而树链剖分不支持动态维护树上的拓扑结构。所以我们需要Link-Cut Tree(lct)来解决这种动态树问题。顺带一提的是,动态树也是Tarjan发明的。

首先我们介绍一个概念:Preferred path(实边),其他的边都是虚边。我们使用splay来实时地维护这条路径。

lct的核心操作是access。access操作可以把虚边变为实边,通过改变splay的拓扑结构来维护实边。

有了这个数据结构,我们依次来考虑两个操作。

对于链接两个节点,我们需要首先把x节点变为他所在树的根节点,然后直接令fa[x] = y即可。

怎样换根呢?稍微思考一下可以发现,我们直接把从根到他的路径反转即可。

对于第二种操作,我们直接断开拓扑关系即可。

另外实现的时候要注意,splay的根节点的父亲是他的上一个节点。所以zig和splay的写法应该格外注意。

Code

  1. #include <algorithm>
  2. #include <cctype>
  3. #include <cstdio>
  4. #include <stack>
  5. using std::stack;
  6. const int maxn = 10005;
  7. inline int read() {
  8. int x = 0, f = 1;
  9. char ch = getchar();
  10. while (!isdigit(ch)) {
  11. if (ch == '-')
  12. f = -1;
  13. ch = getchar();
  14. }
  15. while (isdigit(ch)) {
  16. x = x * 10 + ch - '0';
  17. ch = getchar();
  18. }
  19. return x * f;
  20. }
  21. int n, m;
  22. int fa[maxn], ch[maxn][2];
  23. bool rev[maxn];
  24. inline bool isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; }
  25. void pushdown(int k) {
  26. if (rev[k]) {
  27. rev[k] = 0;
  28. rev[ch[k][0]] ^= 1;
  29. rev[ch[k][1]] ^= 1;
  30. std::swap(ch[k][0], ch[k][1]);
  31. }
  32. }
  33. void zig(int x) {
  34. int y = fa[x], z = fa[y], l = (ch[y][1] == x), r = l ^ 1;
  35. if (!isroot(y))
  36. ch[z][ch[z][1] == y] = x;
  37. fa[ch[y][l] = ch[x][r]] = y;
  38. fa[ch[x][r] = y] = x;
  39. fa[x] = z;
  40. }
  41. void splay(int x) {
  42. stack<int> st;
  43. st.push(x);
  44. for (int i = x; !isroot(i); i = fa[i])
  45. st.push(fa[i]);
  46. while (!st.empty()) {
  47. pushdown(st.top());
  48. st.pop();
  49. }
  50. for (int y = fa[x]; !isroot(x); zig(x), y = fa[x])
  51. if (!isroot(y))
  52. zig((ch[fa[y]][0] == y) == (ch[y][0] == x) ? y : x);
  53. }
  54. void access(int x) {
  55. int t = 0;
  56. while (x) {
  57. splay(x);
  58. ch[x][1] = t;
  59. t = x;
  60. x = fa[x];
  61. }
  62. }
  63. void rever(int x) {
  64. access(x);
  65. splay(x);
  66. rev[x] ^= 1;
  67. }
  68. void link(int x, int y) {
  69. rever(x);
  70. fa[x] = y;
  71. splay(x);
  72. }
  73. void cut(int x, int y) {
  74. rever(x);
  75. access(y);
  76. splay(y);
  77. ch[y][0] = fa[x] = 0;
  78. }
  79. int find(int x) {
  80. access(x);
  81. splay(x);
  82. int y = x;
  83. while (ch[y][0])
  84. y = ch[y][0];
  85. return y;
  86. }
  87. int main() {
  88. #ifndef ONLINE_JUDGE
  89. freopen("input", "r", stdin);
  90. #endif
  91. char ch[10];
  92. int x, y;
  93. n = read(), m = read();
  94. for (int i = 1; i <= m; i++) {
  95. scanf("%s", ch);
  96. x = read();
  97. y = read();
  98. if (ch[0] == 'C')
  99. link(x, y);
  100. else if (ch[0] == 'D')
  101. cut(x, y);
  102. else {
  103. if (find(x) == find(y))
  104. printf("Yes\n");
  105. else
  106. printf("No\n");
  107. }
  108. }
  109. }

[bzoj2049][Sdoi2008]Cave 洞穴勘测——lct的更多相关文章

  1. [BZOJ2049][Sdoi2008]Cave 洞穴勘测 LCT模板

    2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 9705  Solved: 4674[Submit] ...

  2. [BZOJ2049] [SDOI2008] Cave 洞穴勘测 (LCT)

    Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好 ...

  3. bzoj2049: [Sdoi2008]Cave 洞穴勘测 lct裸题

    题意:三种操作一种摧毁一条边,一种链接一条边,一种查询两个点是否联通 题解:lct的link和cut即可 /********************************************** ...

  4. BZOJ2049 SDOI2008 Cave 洞穴勘测 【LCT】

    BZOJ2049 SDOI2008 Cave 洞穴勘测 Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分 ...

  5. 【LCT】BZOJ2049 [SDOI2008]Cave 洞穴勘测

    2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 10059  Solved: 4863[Submit ...

  6. bzoj 2049: [Sdoi2008]Cave 洞穴勘测 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2049 题面: 2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 1 ...

  7. BZOJ 2049: [Sdoi2008]Cave 洞穴勘测 LCT

    2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnli ...

  8. [bzoj2049][Sdoi2008]Cave 洞穴勘测_LCT

    Cave 洞穴勘测 bzoj-2049 Sdoi-2008 题目大意:维护一个数据结构,支持森林中加边,删边,求两点连通性.n个点,m个操作. 注释:$1\le n\le 10^4$,$1\le m\ ...

  9. 【BZOJ2049】 [Sdoi2008]Cave 洞穴勘测 LCT/并查集

    两种方法: 1.LCT 第一次LCT,只有link-cut和询问,无限T,到COGS上找了数据,发现splay里的父亲特判出错了(MD纸张),A了,好奇的删了反转T了.... #include < ...

随机推荐

  1. [转][赞]Android开发者必知的开发资源

    英文原文:Bongzimo  翻译: ImportNew-黄小非 随着Android平台市场份额的持续猛增 ,越来越多的开发者开始投入Android应用程序的开发大潮.如果您是一位2013年刚刚入行的 ...

  2. Loadrunner11.0安装与简单使用

    公司开发了APP或者微信小程序啊什么的,都会先进行性能测试,而性能测试一般肯定会来测试接口的压测,并发.Loadrunner是一个很强大的测试工具,它是一种预测系统行为和性能的负载测试工具.通过以模拟 ...

  3. JS运行在服务器端注意事项

    <script runat="server" language="javascript"> </script> 1. ASP利于JS重载 ...

  4. 《python机器学习—预测分析核心算法》:构建预测模型的一般流程

    参见原书1.5节 构建预测模型的一般流程 问题的日常语言表述->问题的数学语言重述重述问题.提取特征.训练算法.评估算法 熟悉不同算法的输入数据结构:1.提取或组合预测所需的特征2.设定训练目标 ...

  5. %matplotlib inline

    整理摘自 https://zhidao.baidu.com/question/1387744870700677180.html %matplotlib inline是jupyter notebook里 ...

  6. 九度OJ--1167(C++)

    #include <iostream>#include <algorithm>#include <map> using namespace std; int mai ...

  7. memcached的认识

    <?php /* memcached概念: Memcached是一个免费开源的,高性能的,具有分布式对象的缓存系统,它可以用来保存一些经常存取的对象或数据,保存的数据像一张巨大的HASH表,该表 ...

  8. [译]如何去除Git的unstaged的文件提示“old mode 100755 new mode 100644”?

    原文来源:https://stackoverflow.com/questions/1257592/how-do-i-remove-files-saying-old-mode-100755-new-mo ...

  9. 关于<!DOCTYPE html>的学习(转)

    DOCTYPE是对Document type的缩写,说明用XHTML或者HTML是什么版本的.必须出现在<html>标签的前面,不需要关闭标签. <!DOCTYPE>声明不是标 ...

  10. 物联网PPT智能家居王思齐和陈由钧第10组

    ppt做完了但是不知道怎么用博客园发ppt!只能发几个图片了