传送门

突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288

首先有两个操作,一个查询,一个连接

查询的话,直接在树上建主席树

然后难点在于连接

用启发式合并就可以了(想了半天都没想出来)

每次合并时,我们把小的树接到大的上,然后dfs一遍小的树,更新信息

然后注意数组……别太小也别太大……(被数组大小坑了好几次提交)

  1. //minamoto
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  5. char buf[<<],*p1=buf,*p2=buf;
  6. inline int read(){
  7. #define num ch-'0'
  8. char ch;bool flag=;int res;
  9. while(!isdigit(ch=getc()))
  10. (ch=='-')&&(flag=true);
  11. for(res=num;isdigit(ch=getc());res=res*+num);
  12. (flag)&&(res=-res);
  13. #undef num
  14. return res;
  15. }
  16. char obuf[<<],*o=obuf;
  17. void print(int x){
  18. if(x>) print(x/);
  19. *o++=x%+;
  20. }
  21. const int N=,M=N*;
  22. int ver[N<<],Next[N<<],head[N];
  23. int a[N],fa[N],sz[N],b[N];
  24. int n,m,tot,q,size,ans;
  25. void add(int u,int v){
  26. ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
  27. ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
  28. }
  29. int L[M],R[M],sum[M],rt[N],cnt;
  30. void update(int last,int &now,int l,int r,int x){
  31. sum[now=++cnt]=sum[last]+;
  32. if(l==r) return;
  33. int mid=(l+r)>>;
  34. if(x<=mid) R[now]=R[last],update(L[last],L[now],l,mid,x);
  35. else L[now]=L[last],update(R[last],R[now],mid+,r,x);
  36. }
  37. int query(int u,int v,int lca,int lca_fa,int l,int r,int k){
  38. if(l>=r) return l;
  39. int x=sum[L[v]]+sum[L[u]]-sum[L[lca]]-sum[L[lca_fa]];
  40. int mid=(l+r)>>;
  41. if(x>=k) return query(L[u],L[v],L[lca],L[lca_fa],l,mid,k);
  42. else return query(R[u],R[v],R[lca],R[lca_fa],mid+,r,k-x);
  43. }
  44. inline int hash(int x){
  45. return lower_bound(b+,b++size,x)-b;
  46. }
  47. int ff(int x){
  48. return fa[x]==x?x:fa[x]=ff(fa[x]);
  49. }
  50. int st[N][],d[N],vis[N];
  51. void dfs(int u,int father,int root){
  52. st[u][]=father;
  53. for(int i=;i<=;++i)
  54. st[u][i]=st[st[u][i-]][i-];
  55. ++sz[root];
  56. d[u]=d[father]+;
  57. fa[u]=root;
  58. vis[u]=;
  59. update(rt[father],rt[u],,size,hash(a[u]));
  60. for(int i=head[u];i;i=Next[i]){
  61. int v=ver[i];
  62. if(v==father) continue;
  63. dfs(v,u,root);
  64. }
  65. }
  66. int LCA(int x,int y){
  67. if(x==y) return x;
  68. if(d[x]<d[y]) swap(x,y);
  69. for(int i=;i>=;--i){
  70. if(d[st[x][i]]>=d[y]) x=st[x][i];
  71. }
  72. if(x==y) return x;
  73. for(int i=;i>=;--i){
  74. if(st[x][i]!=st[y][i])
  75. x=st[x][i],y=st[y][i];
  76. }
  77. return st[x][];
  78. }
  79. int main(){
  80. //freopen("testdata.in","r",stdin);
  81. int t=read();
  82. n=read(),m=read(),q=read();
  83. for(int i=;i<=n;++i)
  84. a[i]=b[i]=read(),fa[i]=i;
  85. sort(b+,b++n);
  86. size=unique(b+,b++n)-b-;
  87. for(int i=;i<=m;++i){
  88. int u=read(),v=read();
  89. add(u,v);
  90. }
  91. for(int i=;i<=n;++i)
  92. if(!vis[i]) dfs(i,,i);
  93. while(q--){
  94. char ch;int x,y;
  95. while(!isupper(ch=getc()));
  96. x=read()^ans,y=read()^ans;
  97. if(ch=='Q'){
  98. int k=read()^ans;
  99. int lca=LCA(x,y);
  100. ans=b[query(rt[x],rt[y],rt[lca],rt[st[lca][]],,size,k)];
  101. print(ans),*o++='\n';
  102. }
  103. else{
  104. add(x,y);
  105. int u=ff(x),v=ff(y);
  106. if(sz[u]<sz[v]) swap(x,y),swap(u,v);
  107. dfs(y,x,u);
  108. }
  109. }
  110. fwrite(obuf,o-obuf,,stdout);
  111. return ;
  112. }

[bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)的更多相关文章

  1. P3302 [SDOI2013]森林(主席树+启发式合并)

    P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...

  2. bzoj3123 [Sdoi2013]森林 树上主席树+启发式合并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3123 题解 如果是静态的查询操作,那么就是直接树上主席树的板子. 但是我们现在有了一个连接两棵 ...

  3. BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并

    BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20 ...

  4. BZOJ2123 [Sdoi2013]森林 【主席树 + 启发式合并】

    题目 输入格式 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...

  5. bzoj 3123 [Sdoi2013]森林(主席树+启发式合并+LCA)

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

  6. [luoguP3302] [SDOI2013]森林(主席树 + 启发式合并 + lca)

    传送门 显然树上第k大直接主席树 如果连边的话,我们重构小的那一棵,连到另一棵上. 说起来简单,调了我一晚上. 总的来说3个错误: 1.离散化写错位置写到了后面 2."="写成了& ...

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

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

  8. p3302 [SDOI2013]森林(树上主席树+启发式合并)

    对着题目yy了一天加上看了一中午题解,终于搞明白了我太弱了 连边就是合并线段树,把小的集合合并到大的上,可以保证规模至少增加一半,复杂度可以是\(O(logn)\) 合并的时候暴力dfs修改倍增数组和 ...

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

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

随机推荐

  1. for循环实例

    for循环“池理解”[root@localhost ~]# vi showday.sh#!/bin/bashfor TM in "Morning" "Noon" ...

  2. ztree删除某个节点下的全部子节点后,父节点图标还是文件夹

    <script type="text/javascript"> //删除节点 zTree.removeNode(treeNode); //获取删除节点的父节点 var ...

  3. arm裸机通过uboot运行hello world程序测试结果

    开发板EasyARM i.MX280A CPU:arm926ejs helloworld程序使用的编译器 (1)arm-fsl-linux-gnueabi-gcc  version gcc4.4.4 ...

  4. 【更新】搭建 Zookeeper-3.4.11 集群

    先准备好三台linux(虚拟机). 1. 先把Java环境配好.我CentOS-7-x86_64-DVD-1708 + jdk1.8.0_161 1.1 先把jdk上传到系统里面(我利用的Filezi ...

  5. VS Code折腾记 - (2) 快捷键大全,没有更全

    前言 VSCode的快捷键继承了一些IDE风格,有VS的身影,也有Emacs的身影..简言之,内置快捷键玩熟了,效率提高不是一点两点. VsCode 快捷键有五种组合方式(科普) Ctrl + Shi ...

  6. windows下搭建vue开发环境+IIS部署 [转]

    特别说明:下面任何命令都是在windows的命令行工具下进行输入,打开命令行工具的快捷方式如下图:     详细的安装步骤如下: 一.安装node.js 说明:安装node.js的windows版本后 ...

  7. ajax上传文件及进度显示

    之前在博文:原生ajax写法就提及过ajax2.0与1.0的差别是多了FormData和利用FormData文件上传(当然还有跨域,但不是本文的重点). 那么具体怎么样实现ajax上传文件呢? 一般来 ...

  8. nltk——文本分类

      sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003 ...

  9. saltstack 基本操作

    一.常用操作 ①.模块查看 #查看全部模块 [root@k8s_master ~]# salt '*' sys.list_modules # "*"为所有node节点 (此处可以写 ...

  10. JAVA记录-Spring两大特性

    1.IOC控制反转 Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象 ...