题目链接 BZOJ

洛谷

详见这.

求所有点到某个点距离和最短,即求树的重心。考虑如何动态维护。

两棵子树合并后的重心一定在两棵树的重心之间那条链上,所以在合并的时候用启发式合并,每合并一个点检查sz[]大的那棵子树的重心(记为root)最大子树的sz[]*2是否>n;

若>n,则向fa移动一次(先把合并点Splay到根)。重心还一定是在sz[]大的那棵子树中,且移动次数不会超过sz[]小的子树的点数(所以总移动次数不会超过O(n)?)。

复杂度 \(O(nlog^2n)\)

具体实现。。想通了真是特别简单。。也就想想简单

先Link,然后从心向右中序遍历(深度大是向右!).

每到一个点判断其右子树和虚树的sz和*2是否>当前根的sz,如果是,则当前点是要找的重心,继续下一个。若sz[x]*2<sz[root],那么root就是根了。

可能有多个重心,这些重心应该是连续的一段。因为编号最小,若sz[x] * 2==sz[root] && id[x]<id[root],则更新root继续。

用并查集维护重心。(Find_root()太慢了)

另外不需要再算左子树取max,及深度小于它的子树大小,因为既然重心在那边就不会大过另一边,更何况另一边还又插入了一棵子树。

维护子树最大值找重心好像不行吧,合并更新好像很麻烦,直接用sz[]就可以找。

注意用点的sz[]前先Splay()更新!

至于更新重心可以通过缩短左右区间 能到O(nlogn)的方法(还比这个好理解?)以后再做吧

为什么一定要Make_root()重心。。突然觉得根本不明白LCT,不知道怎么走的了。唉以后再说吧。。先水过去

  1. //4044kb 2256ms
  2. #include <cstdio>
  3. #include <cctype>
  4. #include <algorithm>
  5. #define gc() getchar()
  6. const int N=1e5+5;
  7. #define lson son[x][0]
  8. #define rson son[x][1]
  9. int n,m,Ans,sz[N],sz_i[N],_fa[N],fa[N],son[N][2],sk[N];
  10. bool tag[N];
  11. inline void Update(int x){
  12. sz[x]=sz[lson]+sz[rson]+sz_i[x]+1;
  13. }
  14. inline bool n_root(int x){
  15. return son[fa[x]][0]==x||son[fa[x]][1]==x;
  16. }
  17. inline void Rev(int x){
  18. std::swap(lson,rson), tag[x]^=1;
  19. }
  20. inline void PushDown(int x){
  21. if(tag[x]) Rev(lson),Rev(rson),tag[x]=0;
  22. }
  23. void Rotate(int x)
  24. {
  25. int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
  26. if(n_root(a)) son[b][son[b][1]==a]=x;
  27. if(son[x][r]) fa[son[x][r]]=a;
  28. fa[a]=x, fa[x]=b, son[a][l]=son[x][r], son[x][r]=a;
  29. Update(a);
  30. }
  31. void Splay(int x)
  32. {
  33. int t=1,a=x; sk[1]=x;
  34. while(n_root(a)) sk[++t]=a=fa[a];
  35. while(t) PushDown(sk[t--]);
  36. while(n_root(x))
  37. {
  38. a=fa[x];
  39. if(n_root(a)) Rotate(son[a][1]==x^son[fa[a]][1]==a?x:a);
  40. Rotate(x);
  41. }
  42. Update(x);
  43. }
  44. void Access(int x){
  45. for(int pre=0; x; x=fa[pre=x])
  46. Splay(x), sz_i[x]+=sz[rson]-sz[pre], rson=pre;//Update(x);
  47. }
  48. void Make_root(int x){
  49. Access(x), Splay(x), Rev(x);
  50. }
  51. void Split(int x,int y){
  52. Make_root(x), Access(y), Splay(y);
  53. }
  54. int Find_root(int x)
  55. {
  56. Access(x), Splay(x);
  57. while(lson) x=lson;
  58. return x;
  59. }
  60. void Link(int x,int y){
  61. Split(x,y), sz_i[y]+=sz[x], fa[x]=y, Update(y);
  62. }
  63. int Get_fa(int x){
  64. return x==_fa[x]?x:_fa[x]=Get_fa(_fa[x]);
  65. }
  66. //int Next(int x){//?
  67. // PushDown(x), x=rson;
  68. // while(lson) PushDown(x),x=lson;
  69. // return x;
  70. //}
  71. int q[N],cnt;
  72. void DFS(int x,int lim)
  73. {
  74. PushDown(x);
  75. if(lson) DFS(lson,lim);
  76. if(cnt>lim) return;
  77. q[++cnt]=x;
  78. if(cnt>lim) return;
  79. if(rson) DFS(rson,lim);
  80. }
  81. int Union(int x,int y)
  82. {
  83. int r1=Get_fa(x),r2=Get_fa(y);
  84. // int r1=Find_root(x),r2=Find_root(y);
  85. Splay(r1), Splay(r2);//先Splay更新sz[]!
  86. if(sz[r1]>sz[r2]||(sz[r1]==sz[r2]&&y>x)) std::swap(x,y),std::swap(r1,r2);//x->y r1->r2
  87. int lim=sz[r1],res=r2,tot=sz[r2]+sz[r1];
  88. Link(x,y), Access(x), Splay(r2);
  89. cnt=0;
  90. DFS(r2,lim);
  91. for(int sum,i=1; i<=cnt; ++i)
  92. {
  93. Splay(q[i]), sum=sz[son[q[i]][1]]+sz_i[q[i]]+1;
  94. // if(tot<sum<<1) res=q[i];//不这么写是不是有点问题啊
  95. // else if(tot==sum<<1) res=std::min(res,q[i]);
  96. if(tot<sum<<1||(tot==sum<<1&&q[i]<=res)) res=q[i];
  97. else break;
  98. }
  99. Make_root(res);
  100. _fa[r1]=_fa[r2]=_fa[res]=res/*更新重心*/;
  101. return res;
  102. }
  103. inline int read()
  104. {
  105. int now=0;register char c=gc();
  106. for(;!isdigit(c);c=gc());
  107. for(;isdigit(c);now=now*10+c-'0',c=gc());
  108. return now;
  109. }
  110. int main()
  111. {
  112. n=read(),m=read();
  113. int res=0,x,y; char opt[5];
  114. for(int i=1; i<=n; ++i) _fa[i]=i, res^=i, sz[i]=1;
  115. while(m--)
  116. {
  117. scanf("%s",opt);
  118. if(opt[0]=='A') x=read(),y=read(),res^=Get_fa(x)^Get_fa(y)^Union(x,y);
  119. else if(opt[0]=='Q') x=read(),printf("%d\n",Get_fa(x));//printf("%d\n",Find_root(x));
  120. else printf("%d\n",res);
  121. }
  122. return 0;
  123. }

BZOJ.3510.首都(LCT 启发式合并 树的重心)的更多相关文章

  1. BZOJ 3510: 首都 LCT + multiset维护子树信息 + 树的重心

    Code: #include<bits/stdc++.h> #define maxn 200000 #define inf 1000000000 using namespace std; ...

  2. BZOJ 3510 首都 (LCT)

    洛谷P4299传送门 题目大意:给你一颗树,边是一条一条连上去的 在连接过程中会存在询问,询问当前节点所在联通块(其实是一颗树)的重心是哪个节点 以及森林中所有树的重心的异或和 在做这道题之前,要先了 ...

  3. [BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并

    [BZOJ4530][Bjoi2014]大融合 试题描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是 ...

  4. BZOJ 3510 - 首都 「 $LCT$ 动态维护树的重心」

    这题 FlashHu 的优化思路值得借鉴 前置引理 树中所有点到某个点的距离和中,到重心的距离和是最小的. 把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上. 一棵树 ...

  5. BZOJ 3123 [SDOI2013] 森林 - 启发式合并 主席树

    Description 给你一片森林, 支持两个操作: 查询$x$到$y$的$K$大值,  连接两棵树中的两个点 Solution 对每个节点$x$动态开权值线段树, 表示从$x$到根节点路径上权值出 ...

  6. BZOJ2888 资源运输(LCT启发式合并)

    这道题目太神啦! 我们考虑他的每一次合并操作,为了维护两棵树合并后树的重心,我们只好一个一个的把节点加进去.那么这样一来看上去似乎就是一次操作O(nlogn),但是我们拥有数据结构的合并利器--启发式 ...

  7. 【BZOJ-2888】资源运输 LCT + 启发式合并

    2888: 资源运输 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 63  Solved: 33[Submit][Status][Discuss] D ...

  8. 【刷题】BZOJ 3510 首都

    Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从 ...

  9. 4.17 省选模拟赛 远行 LCT 启发式合并 倍增

    容易写出nQ的暴力 由于数据是期望的时间 所以直接dfs可以跑的很快 可以拿到70分. 当然 可以进一步优化暴力 使用换根dp 然后可以将暴力优化到n^2. const int MAXN=300010 ...

随机推荐

  1. Cpp读文件、CString转String、String转CString

    场景 C++读取文件 技术点 读取文件 fstream提供了三个类,用来实现c++对文件的操作.(文件的创建.读.写). ifstream -- 从已有的文件读入 ofstream -- 向文件写内容 ...

  2. grep用法【转】

    简介 grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它 ...

  3. jvm系列六、windows用jdk自带工具jps、jstack找出性能最差的代码

    一.运行程序TestGC 二.用jps找出当前应用的进程号PID 到jdk安装目录的bin目录下输入: jps -l PID为1264 三.启动Process Explorer(下载地址:https: ...

  4. sqlserver 日志传送

    可以使用日志传送将事务日志不间断地从一个数据库(主数据库)发送到另一个数据库(辅助数据库).不间断地备份主数据库中的事务日志,然后将它们复制并还原到辅助数据库,这将使辅助数据库与主数据库基本保持同步. ...

  5. Ext需要的文件目录

    使用ext版本信息:ext-4.1.1a <!-- 下面是引入文件需要导入的文件信息 ext-all.css ext-all.js --><link rel="styles ...

  6. 使用Eclipse创建Web Services

    正文: 项目源文件: 百度云盘/博客园/project/wsServerExample/wsServerExample.rar 参考文献: http://www.ibm.com/developerwo ...

  7. MySQL数据库排序选择的作用和该如何选择编码格式

    前言:在创建数据库的时候,会有这样一个选项->排序规则,平时在创建数据库的时候并没有注意,只是选择了默认,也没感觉有什么问题,今天看到这个突然好奇起来,所以看了一些资料做了以下的一些总结,若有错 ...

  8. InterruptedException 异常

    当一个方法后面声明可能会抛出InterruptedException 异常时,说明该方法是可能会花一点时间,但是可以取消的方法. 抛InterruptedException的代表方法有: 1. jav ...

  9. bzoj 1060

    这题其实有点骗人... 通过观察很容易发现:考虑某一些叶节点的LCA,由于根节点到这个LCA的距离唯一,故要求这些叶节点到这一LCA的距离都相等 于是我们仅需dfs,找到次底层的节点,然后使这些节点的 ...

  10. 格式化输出的方法:%、.format()、f

    a = '123'a1 = '456'a2 = '789' %占位符 text = "a=%s"%atext1 = "a=%s,a1=%s,a2=%s"%(a, ...