3123: [Sdoi2013]森林

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 4813  Solved: 1420
[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。之后的操作类似。

思路:题意输入的case不要管,此题不是多组输入。 我们求路径第k大,优先会想到主席树,但是这里有合并的操作,事实上启发式够用了。

至于倍增LCA,我们可以dfs的时候就维护。

  1. #include<bits/stdc++.h>
  2. #define rep(i,a,b) for(int i=a;i<=b;i++)
  3. using namespace std;
  4. const int maxn=;
  5. struct in{
  6. int l,r,sum;
  7. in(){l=r=sum=;}
  8. in(int L,int R,int S):l(L),r(R),sum(S){}
  9. }s[];
  10. int Laxt[maxn],Next[maxn<<],To[maxn<<],rt[maxn],cnt,scc_cnt,N,ans;
  11. int a[maxn],b[maxn],fa[maxn][],tot,scc[maxn],sz[maxn],dep[maxn],num;
  12. void read(int &x){
  13. x=; char c=getchar();
  14. while(c>''||c<'') c=getchar();
  15. while(c>=''&&c<='') x=x*+c-'',c=getchar();
  16. }
  17. void add(int u,int v){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;}
  18. void update(int &Now,int pre,int L,int R,int pos)
  19. {
  20. Now=++num; s[Now]=s[pre]; s[Now].sum++;
  21. if(L==R) return ; int Mid=(L+R)>>;
  22. if(pos<=Mid) update(s[Now].l,s[pre].l,L,Mid,pos);
  23. else update(s[Now].r,s[pre].r,Mid+,R,pos);
  24. }
  25. void dfs(int u,int f,int p)
  26. {
  27. update(rt[u],rt[f],,tot,a[u]); dep[u]=dep[f]+;
  28. fa[u][]=f; scc[u]=p; sz[p]++;
  29. rep(j,,) fa[u][j]=fa[fa[u][j-]][j-];
  30. for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f) dfs(To[i],u,p);
  31. }
  32. void Connect(int x,int y)
  33. {
  34. if(sz[scc[x]]<sz[scc[y]]) swap(x,y);
  35. dfs(y,x,scc[x]);
  36. }
  37. int query(int u,int v,int Lca,int old,int L,int R,int k)
  38. {
  39. if(L==R) return L; int Mid=(L+R)>>;
  40. int tmp=s[s[u].l].sum+s[s[v].l].sum-s[s[Lca].l].sum-s[s[old].l].sum;
  41. if(tmp>=k) return query(s[u].l,s[v].l,s[Lca].l,s[old].l,L,Mid,k);
  42. return query(s[u].r,s[v].r,s[Lca].r,s[old].r,Mid+,R,k-tmp);
  43. }
  44. int LCA(int u,int v)
  45. {
  46. if(dep[u]<dep[v]) swap(u,v);
  47. for(int i=;i>=;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
  48. if(u==v) return u;
  49. for(int i=;i>=;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
  50. return fa[u][];
  51. }
  52. void Query(int u,int v,int k)
  53. {
  54. int Lca=LCA(u,v);
  55. ans=b[query(rt[u],rt[v],rt[Lca],rt[fa[Lca][]],,tot,k)];
  56. printf("%d\n",ans);
  57. }
  58. int main()
  59. {
  60. int C,M,T,u,v,x,y,k;
  61. scanf("%d%d%d%d",&C,&N,&M,&T);
  62. rep(i,,N) read(a[i]),b[i]=a[i];
  63. sort(b+,b+N+); tot=unique(b+,b+N+)-(b+);
  64. rep(i,,N) a[i]=lower_bound(b+,b+tot+,a[i])-b;
  65. rep(i,,M){
  66. read(u); read(v);
  67. add(u,v); add(v,u);
  68. }
  69. char opt[];
  70. rep(i,,N) if(!scc[i]) dfs(i,,++scc_cnt);
  71. while(T--){
  72. scanf("%s",opt);
  73. if(opt[]=='Q'){
  74. read(x); read(y); read(k);
  75. x=ans^x; y=ans^y; k=ans^k;
  76. Query(x,y,k);
  77. }
  78. else {
  79. scanf("%d%d",&x,&y);
  80. x=ans^x; y=ans^y; add(x,y); add(y,x);
  81. Connect(x,y);
  82. }
  83. }
  84. return ;
  85. }

BZOJ3123: [Sdoi2013]森林(启发式合并&主席树)的更多相关文章

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

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

  2. 【BZOJ3123】[SDOI2013] 森林(启发式合并主席树)

    点此看题面 大致题意: 给你一片森林,有两种操作:询问两点之间的第\(k\)小点权和在两棵树之间连一条边. 前置技能:树上主席树 做这道题目,我们首先要会树上主席树. 关于树上主席树,这有一道很好的例 ...

  3. bzoj 3674: 可持久化并查集加强版 (启发式合并+主席树)

    Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:…… ...

  4. BZOJ 2733 [HNOI2012]永无乡 - 启发式合并主席树

    Description 1: 查询一个集合内的K大值 2: 合并两个集合 Solution 启发式合并主席树板子 Code #include<cstdio> #include<cst ...

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

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

  6. 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并

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

  7. [Sdoi2013]森林(启发式合并+主席树)

    对于操作1,显然可以使用主席树维护,然后对于一条链(x,y),假设lca为f,根为rt,则(rt,x)+(rt,y)-(rt,f)-(rt,fa[f])即为所求的链,在主席树上直接查询即可,查询方式类 ...

  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. SQL SERVER 2008 R2序列号

    SQL SERVER 2008 R2序列号: 数据中心版:PTTFM-X467G-P7RH2-3Q6CG-4DMYB 开 发者 版:MC46H-JQR3C-2JRHY-XYRKY-QWPVM 企    ...

  2. scikit-learn 中常用的评估模型

    一,scikit-learn中常用的评估模型 1.评估分类模型: ​ 2.评估回归模型: ​ 二.常见模型评估解析: •对于二分类问题,可将样例根据其真实类别和分类器预测类别划分为:(T,F表示预测的 ...

  3. [LeetCode]206. Reverse Linked List(链表反转)

    Reverse a singly linked list. click to show more hints. Subscribe to see which companies asked this ...

  4. SQL 根据条件取不同列中的值来排序

    1  有时候排序比较复杂,比如:领导对工资在1000到2000元之间的员工更感兴趣,于是要求工资在这个范围内的员工排在前面,以便优先查看 对于这种要求我们可以在查询中新生成一列,用多列排序的方法处理代 ...

  5. 报错org.openqa.selenium.WebDriverException: disconnected: unable to connect to renderer解决方法

    做自动化时经常会遇到不兼容的问题,比如以下简单的脚本,主要是打开浏览器,然后最大化窗口,打开百度,输入内容搜索,代码如下: package com.gs.selenium; import org.op ...

  6. javascript原生事件总结

    javascript原生的事件,总结了一下,包括事件流.处理函数.事件对象这几样东西.而在兼容性方面,主要是老牌ie8以及以下和现代浏览器的差异,也就是ie和DOM事件标准的差异. 事件流这个事件流i ...

  7. mongo增删改查封装(C#)

    Framework版本:.Net Framework 4 ConnectionUtil源码参见:https://www.cnblogs.com/threadj/p/10536273.html usin ...

  8. TED #03# 10 ways to have a better conversation

    Teach you how to talk and how to listen Many of you have already heard a lot of advice on this, thin ...

  9. pycharm 模板添加作者时间信息

    在pycharm使用过程中,对于每次新建文件的shebang行和关于代码编写者的一些个人信息快捷填写,使用模板的方式比较方便. 方法如下: 1.打开pycharm,选择File-Settings 2. ...

  10. git使用合集

    1.git 克隆时重命名本地文件夹或目录 如:git clone https://github.com/torvalds/linux.git linux_kernel 2.git查看tag git t ...