【BZOJ3510】首都

Description

在X星球上有N个国家,每个国家占据着X星球的一座城市。由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的。 
X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失,而B国的国土也将归A国管辖。A国国王为了加强统治,会在A国和B国之间修建一条公路,即选择原A国的某个城市和B国某个城市,修建一条连接这两座城市的公路。 
同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公路的条数,如果有多个这样的城市,编号最小的将成为首都。 
现在告诉你发生在X星球的战事,需要你处理一些关于国家首都的信息,具体地,有如下3种信息需要处理: 
1、A x y:表示某两个国家发生战乱,战胜国选择了x城市和y城市,在它们之间修建公路(保证其中城市一个在战胜国另一个在战败国)。 
2、Q x:询问当前编号为x的城市所在国家的首都。 
3、Xor:询问当前所有国家首都编号的异或和。

Input

第一行是整数N,M,表示城市数和需要处理的信息数。 
接下来每行是一个信息,格式如题目描述(A、Q、Xor中的某一种)。

Output

输出包含若干行,为处理Q和Xor信息的结果。

Sample Input

10 10
Xor
Q 1
A 10 1
A 1 4
Q 4
Q 10
A 7 6
Xor
Q 7
Xor

Sample Output

11
1
1
1
2
6
2

HINT

对于100%的数据,2<=N<=100000,1<=M<=200000。

题解:考虑每次将小的树合并到大的树上,这样每次大树的重心移动距离不会超过(小树的大小+1),那么我们只需要知道重心移动到了哪里。

可以确定的是,一棵树最多只有相邻的两个重心,所以我们如果想将b接到a的子树上,那么新的重心一定在(原重心-b)的这条链上,并且距离不超过(b树的大小+1),所以我们将对b进行access操作,在对原重心进行splay操作,这样的话这条链上的所有点就都在这棵splay里了,我们可以对splay进行中序遍历,就能将这些点都按顺序拿出来。

那么我们如何确定该以哪个为根呢?我们考虑根从一个点跳到它的儿子时是否会令答案更优,这就需要我们求出每个点的子树大小。我们只需要将当前点splay一下,然后它在LCT中的子树大小就是它在原树中的子树大小了(用LCT维护子树信息的方法不在赘述)。

本题的细节就在于要时刻注意splay,access和计算的顺序,即有时候的子树大小并不是真的大小,还需要进行一系列的操作(或者在进行某些操作后,子树大小就变了),还有别忘了中序遍历的时候需要pushdown。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. using namespace std;
  5. const int maxn=100010;
  6. int n,m,tot,nr,sum;
  7. struct splay
  8. {
  9. int sx,sl,ch[2],fa,rev;
  10. }s[maxn];
  11. int p[maxn];
  12. char str[10];
  13. bool isr(int x) {return s[s[x].fa].ch[0]!=x&&s[s[x].fa].ch[1]!=x;}
  14. void pushup(int x) {s[x].sl=s[x].sx+s[s[x].ch[0]].sl+s[s[x].ch[1]].sl+1;}
  15. void pushdown(int x)
  16. {
  17. if(s[x].rev)
  18. {
  19. swap(s[x].ch[0],s[x].ch[1]),s[x].rev=0;
  20. if(s[x].ch[0]) s[s[x].ch[0]].rev^=1;
  21. if(s[x].ch[1]) s[s[x].ch[1]].rev^=1;
  22. }
  23. }
  24. void updata(int x)
  25. {
  26. if(!isr(x)) updata(s[x].fa);
  27. pushdown(x);
  28. }
  29. void rotate(int x)
  30. {
  31. int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]);
  32. if(!isr(y)) s[z].ch[y==s[z].ch[1]]=x;
  33. s[y].fa=x,s[x].fa=z,s[y].ch[d]=s[x].ch[d^1];
  34. if(s[x].ch[d^1]) s[s[x].ch[d^1]].fa=y;
  35. s[x].ch[d^1]=y;
  36. pushup(y),pushup(x);
  37. }
  38. void splay(int x)
  39. {
  40. updata(x);
  41. while(!isr(x))
  42. {
  43. int y=s[x].fa,z=s[y].fa;
  44. if(!isr(y))
  45. {
  46. if((y==s[z].ch[0])^(x==s[y].ch[0])) rotate(x);
  47. else rotate(y);
  48. }
  49. rotate(x);
  50. }
  51. }
  52. void access(int x)
  53. {
  54. for(int y=0;x;splay(x),s[x].sx-=s[y].sl-s[s[x].ch[1]].sl,s[x].ch[1]=y,pushup(x),y=x,x=s[x].fa);
  55. }
  56. void maker(int x)
  57. {
  58. access(x),splay(x),s[x].rev^=1;
  59. }
  60. void link(int x,int y)
  61. {
  62. maker(x),access(y),splay(y),s[y].sx+=s[x].sl,s[x].fa=y,pushup(y);
  63. }
  64. int findr(int x)
  65. {
  66. access(x),splay(x),pushdown(x);
  67. while(s[x].ch[0]) x=s[x].ch[0],pushdown(x);
  68. return x;
  69. }
  70. void query(int x,int y)
  71. {
  72. if(!x) return ;
  73. pushdown(x);
  74. query(s[x].ch[0],y);
  75. if(p[0]>=y) return ;
  76. p[++p[0]]=x;
  77. if(p[0]>=y) return ;
  78. query(s[x].ch[1],y);
  79. }
  80. int rd()
  81. {
  82. int ret=0,f=1; char gc=getchar();
  83. while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
  84. while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
  85. return ret*f;
  86. }
  87. int main()
  88. {
  89. //freopen("bz3510.in","r",stdin);
  90. n=rd(),m=rd();
  91. int i,j,a,b,c,d,e,sc,sd;
  92. for(i=1;i<=n;i++) s[i].sl=1,sum^=i;
  93. for(i=1;i<=m;i++)
  94. {
  95. scanf("%s",str);
  96. if(str[0]=='X') printf("%d\n",sum);
  97. if(str[0]=='Q') printf("%d\n",findr(rd()));
  98. if(str[0]=='A')
  99. {
  100. a=rd(),b=rd(),c=findr(a),splay(c),d=findr(b),splay(d),sc=s[c].sl,sd=s[d].sl;
  101. if(sc<sd||(sc==sd&&c>d)) swap(c,d),swap(a,b),swap(sc,sd);
  102. link(b,a),access(b),splay(c),p[0]=0,tot=sc+sd,query(c,sd+1),nr=c;
  103. for(j=1;j<=p[0];j++)
  104. {
  105. splay(p[j]);
  106. e=s[p[j]].sx+1+(s[p[j]].ch[1]>0?s[s[p[j]].ch[1]].sl:0);
  107. if(tot-e<e||(tot-e==e&&p[j]<=nr)) nr=p[j];
  108. else break;
  109. }
  110. maker(nr),sum^=nr,sum^=c,sum^=d;
  111. }
  112. }
  113. return 0;
  114. }

【BZOJ3510】首都 LCT维护子树信息+启发式合并的更多相关文章

  1. bzoj3510 首都 LCT 维护子树信息+树的重心

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删 ...

  2. 【bzoj3510】首都 LCT维护子树信息(+启发式合并)

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

  3. 【LCT维护子树信息】uoj207 共价大爷游长沙

    这道题思路方面就不多讲了,主要是通过这题学一下lct维护子树信息. lct某节点u的子树信息由其重链的一棵splay上信息和若干轻儿子子树信息合并而成. splay是有子树结构的,可以在rotate, ...

  4. 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息

    题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量 ...

  5. 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息

    题目描述 给出一棵树和一个点对集合S,多次改变这棵树的形态.在集合中加入或删除点对,或询问集合内的每组点对之间的路径是否都经过某条给定边. 输入 输入的第一行包含一个整数 id,表示测试数据编号,如第 ...

  6. 共价大爷游长沙 lct 维护子树信息

    这个题目的关键就是判断 大爷所有可能会走的路 会不会经过询问的边. 某一条路径经过其中的一条边, 那么2个端点是在这条边的2测的. 现在我们要判断所有的路径是不是都经过 u -> v 我们以u为 ...

  7. $LCT$维护子树信息学习笔记

    \(LCT\)维护子树信息学习笔记 昨天\(FDF\)好题分享投了 \([ZJOI2018]\)历史 这题. 然后我顺势学学这个姿势. 结果调了一年...于是写个笔记记录一下. 基本原理 比较显然地, ...

  8. 洛谷4219 BJOI2014大融合(LCT维护子树信息)

    QWQ 这个题目是LCT维护子树信息的经典应用 根据题目信息来看,对于一个这条边的两个端点各自的\(size\)乘起来,不过这个应该算呢? 我们可以考虑在LCT上多维护一个\(xv[i]\)表示\(i ...

  9. LCT维护子树信息

    有些题目,在要求支持link-cut之外,还会在线询问某个子树的信息.LCT可以通过维护虚边信息完成这个操作. 对于LCT上每个节点,维护两个两sz和si,后者维护该点所有虚儿子的信息,前者维护该点的 ...

随机推荐

  1. django前后端数据传输学习记录

    在开发过程中会遇到这样的情况 后台返回了一堆的数据,是一个列表 例如 datas = [{"a":1, "b":2}, {"c": 3,&q ...

  2. ES6里关于模板字面量的拓展

    JS 的字符串相对其他语言来说功能总是有限的,事实上,ES5中一直缺乏许多特性,如多行字符串.字符串格式化.HTML转义等.ES6通过模板字面量的方式进行了填补,模板字面量试着跳出JS已有的字符串体系 ...

  3. PHP empty()函数说明---用了N遍了就是记不住

    从表面上看,很容易误解empty()函数是判断字符串是否为空的函数,其实并不是,我也因此吃了很多亏. empty()函数是用来测试变量是否已经配置.若变量已存在.非空字符串或者非零,则返回 false ...

  4. Oracle学习——扫盲篇

    前言 近期这几天一直在与Oracle数据库打交道.因为之前对Oracle的学习并不深入,仅仅是把Oracle当成一个数据源去使用.非常多东西了解的不是非常深,比方.数据库.数据库实例.表空间.用户.表 ...

  5. php正则表达式基本

    一.正则表达式的组成 1.分隔符,可以是除了字母,数字,反斜线及空白以外的任何字符,比如/,!,#,%,|,~等;通常有/,!,~ 2.表达式:由一些特殊字符和非特殊字符组成. 3.修饰符:用于开启或 ...

  6. 51单片机 | A/D转换器实现数字电压表实例

    ———————————————————————————————————————————— ADC0809 - - - - - - - - - - - - - - - - - - - - - - - - ...

  7. AutoWare 使用

      1.安装readme当中的要求,安装依赖库   52 sudo apt-get install ros-indigo-desktop-full ros-indigo-nmea-msgs ros-i ...

  8. SQL 怎样 远程备份数据库到本地

    SQL 怎样 远程备份数据库到本地 --1.启用xp_cmdshell USE master EXEC sp_configure 'show advanced options', 1 RECONFIG ...

  9. c#关于int(或其他类型)的字段在对象初始化时默认初始化问题的解决方法

    问题: c#的wcf服务接口在后台通过自定义对象接收前台参数的时候,前台参数即使不传int类型的字段值,后台也会默认初始化为0,由于很多表示状态的int字段都是从0开始的,导致查询的时候有些不想参与查 ...

  10. .Net Framework 与 SQL Server 2005 混乱的时间最大最小值

    Net Framewrok 中,DateTime.MinValue => 0001/01/01 00:00:00SqlDateTime.MinValue.Value  => 1753/01 ...