3123: [Sdoi2013]森林

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 3336  Solved: 978
[Submit][Status][Discuss]

Description

Input

第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。 
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。 
 接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

Output

对于每一个第一类操作,输出一个非负整数表示答案。

Sample Input

1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6

Sample Output

2
2
1
4
2

HINT

对于第一个操作 Q 8 7 3,此时 lastans=0,所以真实操作为Q 8^0 7^0 3^0,也即Q 8 7 3。点8到点7的路径上一共有5个点,其权值为4 1 1 2 4。这些权值中,第三小的为 2,输出 2,lastans变为2。对于第二个操作 Q 3 5 1 ,此时lastans=2,所以真实操作为Q 3^2 5^2 1^2 ,也即Q 1 7 3。点1到点7的路径上一共有4个点,其权值为 1 1 2 4 。这些权值中,第三小的为2,输出2,lastans变为 2。之后的操作类似。

Source

 
  1. /*
  2. 平常这种题很常见的思路就是求出dfs序来,然后每次查询的时候就是在主席树上查询 x+y-lca-fa[lca] 的值就行了。
  3. 但是这个题要动态的给森林中加边,还是强制在线的,所以就需要考虑换一种方法来维护这个东西。
  4. 首先先dfs出每棵树来,然后对于link操作,可以启发式合并两个主席树。这里我们把主席树维护的dfs序变成维护每个点到根的这条路径。所里link的时候假设我们要把x合到y上,那么我们就边dfs x 这棵树,边用当前点的fa作为历史状态的root来更新当前点的root就行了。求lca的fa数组和deep数组在dfs的时候动态维护就行了。
  5. 复杂度: O(nlog2n)
  6. */
  7. #include<cstdio>
  8. #include<iostream>
  9. using namespace std;
  10. const int N=1e5+;
  11. const int M=2e7+;
  12. const int inf=1e9;
  13. int n,m,T,sz,num,ans,val[N],dep[N],siz[N],belong[N],fa[N][];bool flag[N];
  14. struct edge{int u,v,next;}e[N<<];int tot,head[N];
  15. int root[N],R[N],sum[M],ls[M],rs[M];
  16. inline int read(){
  17. int x=;char ch=getchar();
  18. while(ch<''||ch>''){ch=getchar();}
  19. while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
  20. return x;
  21. }
  22. inline void add(int x,int y){
  23. e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
  24. e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
  25. }
  26. void insert(int &k,int last,int l,int r,int pos){
  27. k=++sz;
  28. sum[k]=sum[last]+;
  29. if(l==r) return ;
  30. ls[k]=ls[last];
  31. rs[k]=rs[last];
  32. int mid=l+r>>;
  33. if(pos<=mid) insert(ls[k],ls[last],l,mid,pos);
  34. else insert(rs[k],rs[last],mid+,r,pos);
  35. }
  36. void dfs(int x,int f,int now){
  37. flag[x]=;siz[x]=;belong[x]=now;
  38. for(int i=;i<;i++) fa[x][i]=fa[fa[x][i-]][i-];
  39. insert(root[x],root[f],,inf,val[x]);
  40. for(int i=head[x];i;i=e[i].next){
  41. if(e[i].v!=f){
  42. fa[e[i].v][]=x;
  43. dep[e[i].v]=dep[x]+;
  44. dfs(e[i].v,x,now);
  45. siz[x]+=siz[e[i].v];
  46. }
  47. }
  48. }
  49. inline int lca(int a,int b){
  50. if(dep[a]<dep[b]) swap(a,b);
  51. int t=dep[a]-dep[b];
  52. for(int i=;i<;i++){
  53. if(t&(<<i)){
  54. a=fa[a][i];
  55. }
  56. }
  57. if(a==b) return a;
  58. for(int i=;~i;i--){
  59. if(fa[a][i]!=fa[b][i]){
  60. a=fa[a][i];
  61. b=fa[b][i];
  62. }
  63. }
  64. return fa[a][];
  65. }
  66. int query(int l,int r,int x1,int x2,int x3,int x4,int pos){
  67. if(l==r) return l;
  68. int now=sum[ls[x1]]+sum[ls[x2]]-sum[ls[x3]]-sum[ls[x4]];
  69. int mid=l+r>>;
  70. if(now>=pos) return query(l,mid,ls[x1],ls[x2],ls[x3],ls[x4],pos);
  71. return query(mid+,r,rs[x1],rs[x2],rs[x3],rs[x4],pos-now);
  72. }
  73. int main(){
  74. freopen("forest.in","r",stdin);
  75. freopen("forest.out","w",stdout);
  76. T=read();n=read();m=read();T=read();
  77. for(int i=;i<=n;i++) val[i]=read();
  78. for(int i=,x,y;i<=m;i++) x=read(),y=read(),add(x,y);
  79. for(int i=;i<=n;i++) if(!flag[i]) dfs(i,,++num),R[num]=i;
  80. for(int x,y,z,anc;T--;){
  81. char ch;
  82. for(ch=getchar();ch!='Q'&&ch!='L';ch=getchar());
  83. x=read();y=read();
  84. x^=ans;y^=ans;
  85. if(ch=='Q'){
  86. z=read();z^=ans;
  87. anc=lca(x,y);
  88. ans=query(,inf,root[x],root[y],root[anc],root[fa[anc][]],z);
  89. printf("%d\n",ans);
  90. }
  91. else{
  92. if(siz[R[belong[x]]]>siz[R[belong[y]]]) swap(x,y);
  93. add(y,x);
  94. fa[x][]=y;
  95. siz[R[belong[y]]]+=siz[R[belong[x]]];
  96. dep[x]=dep[y]+;
  97. dfs(x,y,belong[y]);
  98. }
  99. }
  100. return ;
  101. }
  102. /*10
  103. #include<cstdio>
  104. #include<cstring>
  105. #include<algorithm>
  106. using namespace std;
  107. typedef long long ll;
  108.  
  109. #define setfire(name) freopen(#name".in","r",stdin);freopen(#name".out","w",stdout);
  110. #define fre(name) freopen(#name".txt","r",stdin);
  111. #ifdef WIN32
  112. #define LL "%lld"
  113. #else
  114. #define LL "%I64d"
  115. #endif
  116.  
  117. const int N=1e5+5;
  118. int cas,n,m,t,ans,val[N],tv[N],stack[N],prev[N];bool vis[N];
  119. struct edge{int v,next;}e[N<<1];int tot,head[N];
  120. char s[50];
  121.  
  122. inline int read(){
  123. int x=0;char ch=getchar();
  124. while(ch<'0'||ch>'9'){ch=getchar();}
  125. while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
  126. return x;
  127. }
  128. inline void add(int x,int y){
  129. e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
  130. e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
  131. }
  132. inline void bfs(int S,int T){
  133. int top=1;stack[top]=S;
  134. memset(vis,0,(n+2));
  135. memset(prev,0,(n+2)<<2);
  136. while(top){
  137. int x=stack[top--];
  138. for(int i=head[x];i;i=e[i].next){
  139. if(!vis[e[i].v]){
  140. vis[e[i].v]=1;
  141. prev[e[i].v]=x;
  142. if(e[i].v==T) return ;
  143. stack[++top]=e[i].v;
  144. }
  145. }
  146. }
  147. }
  148. inline void calc(int S,int T,int rk){
  149. tv[0]=0;
  150. for(int i=T;i!=S;i=prev[i]) tv[++tv[0]]=val[i];tv[++tv[0]]=val[S];
  151. nth_element(tv+1,tv+rk,tv+tv[0]+1);
  152. printf("%d\n",ans=tv[rk]);
  153. }
  154. void init(){
  155. tot=0;
  156. memset(head,0,(n+2)<<2);
  157. }
  158. int main(){
  159. freopen("forest.in","r",stdin);
  160. freopen("forest.out","w",stdout);
  161. //for(cas=read();init(),cas--;){
  162. cas=read();
  163. n=read();m=read();t=read();
  164. for(int i=1;i<=n;i++) val[i]=read();
  165. for(int i=1,x,y;i<=m;i++) x=read(),y=read(),add(x,y);
  166. for(int x,y,z;t--;){
  167. scanf("%s",s);
  168. if(s[0]=='Q'){
  169. x=read();y=read();z=read();
  170. x^=ans;y^=ans;z^=ans;
  171. bfs(x,y);
  172. calc(x,y,z);
  173. }
  174. else{
  175. x=read();y=read();
  176. x^=ans;y^=ans;
  177. add(x,y);
  178. }
  179. }
  180. // }
  181. return 0;
  182. } */

UPD.2017-04-24

  1. /*
  2. Name: forest
  3. Copyright: @2016-2017 shenben
  4. Author: shenben
  5. Date: 24/04/17 14:56
  6. Description: Algorithm chairman tree & Heuristic mergeing
  7. */
  8. #include<cstdio>
  9. //#include<cstdlib>
  10. #include<iostream>
  11. #include<algorithm>
  12. using namespace std;
  13. const int N=1e5+;
  14. const int M=N*;
  15. struct edge{int v,next;}e[N<<];int tot,head[N];
  16. int n,m,num,cnt,T,sz,a[N],b[N];char s[];
  17. int siz[N],dep[N],fa[N][],R[N],belong[N];bool flag[N];
  18. int root[N],ls[M],rs[M],sum[M];
  19. inline int read(){
  20. int x=,f=;char ch=getchar();
  21. while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
  22. while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
  23. return x*f;
  24. }
  25. void add(int x,int y){
  26. e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
  27. e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
  28. }
  29. void insert(int &k,int last,int l,int r,int x){
  30. k=++sz;
  31. sum[k]=sum[last]+;
  32. if(l==r) return ;
  33. ls[k]=ls[last];
  34. rs[k]=rs[last];
  35. int mid=l+r>>;
  36. if(x<=mid) insert(ls[k],ls[last],l,mid,x);
  37. else insert(rs[k],rs[last],mid+,r,x);
  38. }
  39. int query(int l,int r,int x1,int x2,int x3,int x4,int K){
  40. if(l==r) return l;
  41. int mid=l+r>>;
  42. int cnt=sum[ls[x1]]+sum[ls[x2]]-sum[ls[x3]]-sum[ls[x4]];
  43. if(K<=cnt) return query(l,mid,ls[x1],ls[x2],ls[x3],ls[x4],K);
  44. else return query(mid+,r,rs[x1],rs[x2],rs[x3],rs[x4],K-cnt);
  45. }
  46. void dfs(int x,int f,int now){
  47. flag[x]=;siz[x]=;belong[x]=now;
  48. for(int i=;i<;i++) fa[x][i]=fa[fa[x][i-]][i-];
  49. int p=lower_bound(b+,b+cnt+,a[x])-b;
  50. insert(root[x],root[f],,cnt,p);
  51. for(int i=head[x];i;i=e[i].next){
  52. if(e[i].v!=f){
  53. fa[e[i].v][]=x;
  54. dep[e[i].v]=dep[x]+;
  55. dfs(e[i].v,x,now);
  56. siz[x]+=siz[e[i].v];
  57. }
  58. }
  59. }
  60. inline int lca(int a,int b){
  61. if(dep[a]<dep[b]) swap(a,b);
  62. int t=dep[a]-dep[b];
  63. for(int i=;i<;i++){
  64. if(t&(<<i)){
  65. a=fa[a][i];
  66. }
  67. }
  68. if(a==b) return a;
  69. for(int i=;~i;i--){
  70. if(fa[a][i]!=fa[b][i]){
  71. a=fa[a][i];
  72. b=fa[b][i];
  73. }
  74. }
  75. return fa[a][];
  76. }
  77. int main(){
  78. freopen("forest.in","r",stdin);
  79. freopen("forest.out","w",stdout);
  80. /*int size=64<<20;
  81. char *p=(char *)malloc(size)+size;
  82. __asm__("movl %0,%%esp\n"::"r"(p));*/
  83. T=read();n=read();m=read();T=read();
  84. for(int i=;i<=n;i++) b[i]=a[i]=read();
  85. sort(b+,b+n+);
  86. cnt=unique(b+,b+n+)-(b+);
  87. for(int i=,x,y;i<=m;i++) x=read(),y=read(),add(x,y);
  88. for(int i=;i<=n;i++) if(!flag[i]) flag[i]=,dfs(i,,++num),R[num]=i;
  89. for(int i=,x,y,z,anc,ans=;i<=T;i++){
  90. scanf("%s",s);x=read()^ans;y=read()^ans;
  91. if(s[]=='Q'){
  92. anc=lca(x,y);z=read()^ans;
  93. ans=query(,cnt,root[x],root[y],root[anc],root[fa[anc][]],z);
  94. printf("%d\n",ans=b[ans]);
  95. }
  96. else{
  97. if(siz[R[belong[x]]]>siz[R[belong[y]]]) swap(x,y);
  98. add(x,y);
  99. fa[x][]=y;
  100. dep[x]=dep[y]+;
  101. siz[R[belong[y]]]+=siz[R[belong[x]]];
  102. dfs(x,y,belong[y]);
  103. }
  104. }
  105. fclose(stdin);fclose(stdout);
  106. return ;
  107. }

3123: [Sdoi2013]森林的更多相关文章

  1. BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]

    3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...

  2. bzoj 3123: [Sdoi2013]森林(45分暴力)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4184  Solved: 1235[Submit][Status ...

  3. Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...

  4. ●BZOJ 3123 [Sdoi2013]森林

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3123 题解: 主席树,在线,启发式合并 简单版(只有询问操作):[2588: Spoj 10 ...

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

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

  6. BZOJ 3123 SDOI2013 森林

    首先对于查询操作就是裸的COT QAQ 在树上DFS建出主席树就可以了 对于连接操作,我们发现并没有删除 所以我们可以进行启发式合并,每次将小的树拍扁插入大的树里并重构即可 写完了之后第一个和第二个点 ...

  7. bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)

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

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

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

  9. 【BZOJ】3123: [Sdoi2013]森林

    题解 ------------------ 我莫不是一个智障吧 我把testdata的编号 当成数据组数读进来 我简直有毒 以为哪里写错了自闭了好久 实际上这题很简单,只要愉悦地开个启发式合并,然后每 ...

随机推荐

  1. ES6里关于函数的拓展(三)

    一.箭头函数 在ES6中,箭头函数是其中最有趣的新增特性.顾名思义,箭头函数是一种使用箭头(=>)定义函数的新语法,但是它与传统的JS函数有些许不同,主要集中在以下方面: 1.没有this.su ...

  2. CentOS7下挂载硬盘笔记

    CentOS7下挂载硬盘笔记 准备工作 机器:DELL R730 系统:CentOS 7.4.1708 (Core) x86_64 新增硬盘:三星960PRO 关闭服务器加上新硬盘,然后重启 查看硬盘 ...

  3. mongoDB 删除某一字段、重新名字段

    批量删除字段: {multi:true}:查询到的所有记录都删除. db.collection_name.update({"target_field":{"$exists ...

  4. left menu

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. How to use Variables in different component

    1. In Script Task component Set Value: Dts.Variables["ErrorMsg"].Value = string.Format(&qu ...

  6. extjs_06_grid(列锁定&amp;列分组)

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  7. Memcached进程挂掉自动重启脚本

    vim memcached_check.sh   #!/bin/sh #check memcached process and restart if down PATH=$PATH:/opt/env/ ...

  8. 51单片机 | 使用D/A转换器实现三角波发生器

    ———————————————————————————————————————————— D/A转换器 CS=0.ILE=1时,WR1信号有效时将数据总线上的信号写入8位输入锁存器 XFER=0时,W ...

  9. asp.net中UpdatePanel数据加载成功后回调

    //添加UpdatePanel加载成功后执行的js方法 Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(onPageLoade ...

  10. HTML to PDF pechkin

    1. Goto Nuget 下载 Pechkin 控件 2. 创建需要打印的的PDF controller 和 Action, 这里会调用其他页面的内容进行打印. public ActionResul ...