题意:给定森林,可以把两棵树连起来或者询问链上第k大。

解:启发式合并。

我一开始想到了启发式合并但是发现这样做之后一棵子树就不是一段连续的区间了,那就不能子树xxx了,很迷惘。

后来看了题解发现本来就不需要子树是连续区间......

每次把小的树暴力DFS重构fa[][]和重建主席树。

调了半天是因为lastans没有套上X[]......

注意并查集merge的时候可能有元素为0。无视之即可。

  1. #include <cstdio>
  2. #include <algorithm>
  3.  
  4. const int N = , M = ;
  5.  
  6. struct Edge {
  7. int nex, v;
  8. }edge[N << ]; int top;
  9.  
  10. int X[N], e[N], n, val[N], temp, pw[N], fa[N][], tot, vis[N], father[N], siz[N], d[N], rt[N];
  11. int sum[M], ls[M], rs[M];
  12. char str[];
  13.  
  14. int find(int x) {
  15. if(father[x] == x) {
  16. return x;
  17. }
  18. return father[x] = find(father[x]);
  19. }
  20.  
  21. inline void merge(int x, int y) {
  22. if(!x || !y) {
  23. return;
  24. }
  25. x = find(x);
  26. y = find(y);
  27. if(x == y) {
  28. return;
  29. }
  30. father[x] = y;
  31. siz[y] += siz[x];
  32. return;
  33. }
  34.  
  35. inline bool check(int x, int y) {
  36. return find(x) == find(y);
  37. }
  38.  
  39. inline void add(int x, int y) {
  40. top++;
  41. edge[top].v = y;
  42. edge[top].nex = e[x];
  43. e[x] = top;
  44. return;
  45. }
  46.  
  47. void add(int x, int &y, int p, int l, int r) {
  48. if(!y || y == x) {
  49. y = ++tot;
  50. sum[y] = sum[x];
  51. ls[y] = ls[x];
  52. rs[y] = rs[x];
  53. }
  54. if(l == r) {
  55. sum[y]++;
  56. return;
  57. }
  58. int mid = (l + r) >> ;
  59. if(p <= mid) {
  60. add(ls[x], ls[y], p, l, mid);
  61. }
  62. else {
  63. add(rs[x], rs[y], p, mid + , r);
  64. }
  65. sum[y] = sum[ls[y]] + sum[rs[y]];
  66. return;
  67. }
  68.  
  69. void DFS(int x, int f) {
  70. merge(x, f);
  71. vis[x] = ;
  72. fa[x][] = f;
  73. d[x] = d[f] + ;
  74. for(int j = ; j <= pw[n]; j++) {
  75. fa[x][j] = fa[fa[x][j - ]][j - ];
  76. }
  77. rt[x] = ;
  78. add(rt[f], rt[x], val[x], , temp);
  79. for(int i = e[x]; i; i = edge[i].nex) {
  80. int y = edge[i].v;
  81. if(y == f) {
  82. continue;
  83. }
  84. DFS(y, x);
  85. }
  86. return;
  87. }
  88.  
  89. inline void link(int x, int y) {
  90. if(check(x, y)) {
  91. printf("E1");
  92. exit();
  93. }
  94. if(siz[find(x)] < siz[find(y)]) {
  95. std::swap(x, y);
  96. }
  97. DFS(y, x);
  98. add(x, y);
  99. add(y, x);
  100. return;
  101. }
  102.  
  103. inline int lca(int x, int y) {
  104. if(d[x] > d[y]) {
  105. std::swap(x, y);
  106. }
  107. int t = pw[n];
  108. while(t >= && d[x] != d[y]) {
  109. if(d[fa[y][t]] >= d[x]) {
  110. y = fa[y][t];
  111. }
  112. t--;
  113. }
  114. if(x == y) {
  115. return x;
  116. }
  117. t = pw[n];
  118. while(t >= && fa[x][] != fa[y][]) {
  119. if(fa[x][t] != fa[y][t]) {
  120. x = fa[x][t];
  121. y = fa[y][t];
  122. }
  123. t--;
  124. }
  125. return fa[x][];
  126. }
  127.  
  128. int Ask(int x, int y, int z, int w, int k, int l, int r) {
  129. if(l == r) {
  130. return r;
  131. }
  132. int mid = (l + r) >> , s = ;
  133. s = sum[ls[x]] + sum[ls[y]] - sum[ls[z]] - sum[ls[w]];
  134. if(k <= s) {
  135. return Ask(ls[x], ls[y], ls[z], ls[w], k, l, mid);
  136. }
  137. else {
  138. return Ask(rs[x], rs[y], rs[z], rs[w], k - s, mid + , r);
  139. }
  140. }
  141.  
  142. inline int ask(int x, int y, int k) {
  143. if(!check(x, y)) {
  144. printf("E2");
  145. exit();
  146. }
  147. int z = lca(x, y);
  148. if(d[x] + d[y] - d[z] - d[z] + < k) {
  149. printf("E3");
  150. exit();
  151. }
  152. return Ask(rt[x], rt[y], rt[z], rt[fa[z][]], k, , temp);
  153. }
  154.  
  155. int main() {
  156.  
  157. //freopen("in.in", "r", stdin);
  158. //freopen("my.out", "w", stdout);
  159.  
  160. int m, q;
  161. scanf("%d", &n);
  162. scanf("%d%d%d", &n, &m, &q);
  163. for(int i = ; i <= n; i++) {
  164. scanf("%d", &val[i]);
  165. X[++temp] = val[i];
  166. siz[i] = ;
  167. father[i] = i;
  168. }
  169. for(int i = , x, y; i <= m; i++) {
  170. scanf("%d%d", &x, &y);
  171. add(x, y);
  172. add(y, x);
  173. }
  174. for(int i = ; i <= n; i++) {
  175. pw[i] = pw[i >> ] + ;
  176. }
  177. std::sort(X + , X + temp + );
  178. temp = std::unique(X + , X + temp + ) - X - ;
  179. for(int i = ; i <= n; i++) {
  180. val[i] = std::lower_bound(X + , X + temp + , val[i]) - X;
  181. }
  182. for(int i = ; i <= n; i++) {
  183. if(!vis[i]) {
  184. DFS(i, );
  185. }
  186. }
  187. /// build
  188.  
  189. int lastans = ;
  190. for(int i = , x, y, k; i <= q; i++) {
  191. scanf("%s%d%d", str, &x, &y);
  192. if(str[] == 'L') { // link
  193. link(x ^ lastans, y ^ lastans);
  194. }
  195. else {
  196. scanf("%d", &k);
  197. lastans = X[ask(x ^ lastans, y ^ lastans, k ^ lastans)];
  198. printf("%d\n", lastans);
  199. }
  200. }
  201.  
  202. return ;
  203. }

AC代码

洛谷P3302 森林的更多相关文章

  1. 洛谷$P3302$ 森林 $[SDOI2013]$ 主席树

    正解:主席树 解题报告: 传送门! 口胡一时爽代码火葬场 这题想法不难,,,但显然的是代码应该还挺难打的 但反正我也不放代码,就写下题解趴$QwQ$ 第一问就是个$Count\ on\ a\ tree ...

  2. 洛谷 P3302 [SDOI2013]森林 解题报告

    P3302 [SDOI2013]森林 题目描述 小\(Z\)有一片森林,含有\(N\)个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有\(M\)条边. 小Z希望执行\(T\)个操作,操 ...

  3. 洛谷 P3302 [SDOI2013]森林 Lebal:主席树 + 启发式合并 + LCA

    题目描述 小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有M条边. 小Z希望执行T个操作,操作有两类: Q x y k查询点x到点y路径上所有的权值中,第k小的权 ...

  4. [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)

    传送门 突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288 首先有两个操作,一个查询,一个连接 查询的话,直接 ...

  5. 洛谷 P3302 [SDOI2013]森林

    ->题目链接 题解: #include<queue> #include<cstdio> #include<cstring> #include<iostr ...

  6. 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)

    洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不 ...

  7. 洛谷3月月赛 R1 Step! ZERO to ONE

    洛谷3月月赛 R1 Step! ZERO to ONE 普及组难度 290.25/310滚粗 t1 10分的日语翻译题....太难了不会... t2 真·普及组.略 注意长为1的情况 #include ...

  8. 洛谷P3203 [HNOI2010]弹飞绵羊(LCT,Splay)

    洛谷题目传送门 关于LCT的问题详见我的LCT总结 思路分析 首先分析一下题意.对于每个弹力装置,有且仅有一个位置可以弹到.把这样的一种关系可以视作边. 然后,每个装置一定会往后弹,这不就代表不存在环 ...

  9. 洛谷P4155 [SCOI2015]国旗计划(贪心,树形结构,基数排序)

    洛谷题目传送门 \(O(n)\)算法来啦! 复杂度优化的思路是建立在倍增思路的基础上的,看看楼上几位巨佬的描述吧. 首先数组倍长是一样的.倍增法对于快速找到\(j\)满足\(l_j+m\le r_i\ ...

随机推荐

  1. LCA的一些算法

    LCA,就是求树上任意两点的最近公共祖先 (本题图片与代码均为Luogu3379) 方法我好像讲过一个,这次把主要的三个一起讲一讲 <1> 倍增(O(n log n)) 我们先考虑最基本的 ...

  2. python 井字棋(Tic Tac Toe)

    说明 用python实现了井字棋,整个框架是本人自己构思的,自认为比较满意.另外,90%+的代码也是本人逐字逐句敲的. minimax算法还没完全理解,所以参考了这里的代码,并作了修改. 特点 可以选 ...

  3. 2_C语言中的数据类型 (十)数组

    1          字符串与字符数组 1.1       字符数组定义 char array[100]; 1.2       字符数组初始化 char array[100] = {'a', 'b', ...

  4. Libgdx学习记录14——数据保存Preferences,XmlReader

    在游戏过程过程中,常常需要对某些数据进行保存,以确保下次运行时能够正确读取.如游戏中的金币.道具.游戏分数.已通过的关卡等. Libgdx中常用的数据保存方式有Preferences和XmlReade ...

  5. Arcgis安装要素

    1. ArcGIS安装过程中需将用户名改为计算机名,该计算机名称时需要新建对话框. 2. ArcGIS Server安装过程中要设置ArcGISWebServices用户的读写权限,即设置ASP.NE ...

  6. 利用Kinect实现用指尖隔空控制鼠标(源码放出)

    简介 此程序为利用Kinect实现用手指隔空控制鼠标,是我另一个项目的一部分,因为在另外那个项目中鼠标的click是通过一种特殊的方式实现的,因此这个程序只实现了用手控制鼠标的移动,并没有点击的功能. ...

  7. NetBeans 插件开发简介

    希望 NetBeans 为您提供更多功能吗? 您希望倾心投入到 NetBeans 的开发中,并希望它能激发您开发另一个应用程序的热情.您希望聆听音乐.浏览网页.查看邮件.存储喜欢的 URL,以及维护日 ...

  8. 阿里云配置ssl证书

    一.申请证书和下载证书(阿里云申请) 二.在nginx服务器上配置ssl证书 1.检查服务器是否安装openssl 2.在nginx conf 文件夹创建 cret 文件,放置证书 [root@web ...

  9. Vue.js 相关知识(路由)

    1. 简介 路由,工作原理与路由器相似(路由器将网线总线的IP分发到每一台设备上),Vue中的路由根据用户在网页中的点击,将其引导到对应的页面. 2. 使用步骤 安装vue-router或者直接引入v ...

  10. Notes of Daily Scrum Meeting(12.17)

    我们会尽量安排好时间,在其他作业不受影响的情况下加快项目的进度,在Deadline之前完成Beta阶段的工作. 今天的团队工作总结如下: 团队成员 今日团队工作 陈少杰 调试网络连接,补充后端代码 王 ...