3123: [Sdoi2013]森林

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 2738  Solved: 806
[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

Solution

沃日..这题什么东西..

直接树上主席树启发式合并就好了...

然后我写了3遍..第一遍2&10~13RE其余AC..然后肉眼差错无果..重写第二遍,基本没变,10~13RE...MD再写AC..什么破玩意...

我觉得唯一需要注意的就是LCA合并后要清空,还好我注意到了...

Code

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstring>
  5. #include<algorithm>
  6. using namespace std;
  7. inline int read()
  8. {
  9. int x=0,f=1; char ch=getchar();
  10. while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
  11. while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
  12. return x*f;
  13. }
  14. #define MAXN 100010
  15. int N,M,Q,ls[MAXN],top,val[MAXN],testcase,lastans;
  16. struct EdgeNode{
  17. int next,to;
  18. }edge[MAXN<<1];
  19. int head[MAXN],cnt=1;
  20. inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
  21. inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
  22.  
  23. namespace UF
  24. {
  25. int f[MAXN],size[MAXN];
  26. inline void init() {for (int i=1; i<=N; i++) f[i]=i,size[i]=1;}
  27. inline int F(int x) {if (x==f[x]) return x; return f[x]=F(f[x]);}
  28. inline void Merge(int x,int y) {x=F(x),y=F(y); size[y]+=size[x]; f[x]=y;}
  29. }using namespace UF;
  30. namespace PrTree
  31. {
  32. int lson[MAXN*100],rson[MAXN*100],root[MAXN],sum[MAXN*100],sz;
  33. inline void Insert(int l,int r,int &x,int y,int pos,int val)
  34. {
  35. x=++sz; sum[x]=sum[y]+val;
  36. if (l==r) return;
  37. lson[x]=lson[y],rson[x]=rson[y];
  38. int mid=(l+r)>>1;
  39. if (pos<=mid) Insert(l,mid,lson[x],lson[y],pos,val);
  40. else Insert(mid+1,r,rson[x],rson[y],pos,val);
  41. }
  42. inline int Query(int l,int r,int kth,int a,int b,int c,int d)
  43. {
  44. if (l==r) return l;
  45. int Sum=0,mid=(l+r)>>1;
  46. Sum=sum[lson[a]]+sum[lson[b]]-sum[lson[c]]-sum[lson[d]];
  47. if (Sum<kth)
  48. return Query(mid+1,r,kth-Sum,rson[a],rson[b],rson[c],rson[d]);
  49. else
  50. return Query(l,mid,kth,lson[a],lson[b],lson[c],lson[d]);
  51. }
  52. }using namespace PrTree;
  53. int deep[MAXN],father[18][MAXN];
  54. inline void DFS(int now,int last)
  55. {
  56. PrTree::Insert(1,top,root[now],root[last],val[now],1);
  57. for (int i=1; i<=17; i++)
  58. if (deep[now]>=(1<<i))
  59. father[i][now]=father[i-1][father[i-1][now]];
  60. else father[i][now]=0;
  61. for (int i=head[now]; i; i=edge[i].next)
  62. if (edge[i].to!=last)
  63. {
  64. deep[edge[i].to]=deep[now]+1;
  65. father[0][edge[i].to]=now;
  66. DFS(edge[i].to,now);
  67. }
  68. }
  69. inline int LCA(int x,int y)
  70. {
  71. if (deep[x]<deep[y]) swap(x,y);
  72. int dd=deep[x]-deep[y];
  73. for (int i=0; i<=17; i++)
  74. if (dd&(1<<i)) x=father[i][x];
  75. for (int i=17; i>=0; i--)
  76. if (father[i][x]!=father[i][y])
  77. x=father[i][x],y=father[i][y];
  78. return x==y? x:father[0][x];
  79. }
  80. inline void Link(int x,int y)
  81. {
  82. int fx=F(x),fy=F(y);
  83. InsertEdge(x,y);
  84. if (size[fx]>size[fy])
  85. father[0][y]=x,deep[y]=deep[x]+1,DFS(y,x);
  86. else
  87. father[0][x]=y,deep[x]=deep[y]+1,DFS(x,y);
  88. Merge(x,y);
  89. }
  90. int main()
  91. {
  92. // freopen("tree.in","r",stdin);
  93. // freopen("tree.out","w",stdout);
  94. testcase=read();
  95. N=read(),M=read(),Q=read();
  96. for (int i=1; i<=N; i++) ls[i]=val[i]=read();
  97. sort(ls+1,ls+N+1); top=unique(ls+1,ls+N+1)-ls-1;
  98. for (int i=1; i<=N; i++) val[i]=lower_bound(ls+1,ls+top+1,val[i])-ls;
  99.  
  100. UF::init();
  101. for (int i=1,x,y; i<=M; i++) x=read(),y=read(),InsertEdge(x,y),Merge(x,y);
  102.  
  103. for (int i=1; i<=N; i++) if (!root[i]) DFS(i,0);
  104.  
  105. while (Q--)
  106. {
  107. char opt[2]; scanf("%s",opt+1);
  108. int x,y,z,lca;
  109. switch (opt[1])
  110. {
  111. case 'Q':
  112. x=read(),y=read(),z=read(); x^=lastans,y^=lastans,z^=lastans; lca=LCA(x,y);
  113. printf("%d\n",lastans=ls[PrTree::Query(1,top,z,root[x],root[y],root[lca],root[father[0][lca]])]);
  114. break;
  115. case 'L':
  116. x=read(),y=read(); x^=lastans,y^=lastans; Link(x,y);
  117. break;
  118. }
  119. }
  120. return 0;
  121. }

  

【BZOJ-3123】森林 主席树 + 启发式合并的更多相关文章

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

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

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

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

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

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

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

    我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时 ...

  5. [BZOJ3123][Sdoi2013]森林 主席树+启发式合并

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

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

    题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...

  7. [SDOI2013]森林 主席树+启发式合并

    这题的想法真的很妙啊. 看到题的第一眼,我先想到树链剖分,并把\(DFS\)序当成一段区间上主席树.但是会发现在询问的时候,可能会非常复杂,因为你需要把路径拆成很多条轻链和重链,它们还不一定连续,很难 ...

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

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

  9. 【主席树 启发式合并】bzoj3123: [Sdoi2013]森林

    小细节磕磕碰碰浪费了半个多小时的时间 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M ...

随机推荐

  1. 转载-SVN常用命令

    SVN(Subversion)是一个自由.开源的项目源代码版本控制工具.目前,绝大多数开源软件和企业代码管理,都使用SVN作为代码版本管理软件. Subversion将文件存放在中心版本库里,这个版本 ...

  2. usbnet驱动深入分析-usb虚拟网卡host端【转】

    转自:http://blog.csdn.net/zh98jm/article/details/6339320 1.驱动流程:   2.明确probe函数的功能: probe有usb core 经枚举过 ...

  3. MySQL增量备份与恢复实例【转】

    小量的数据库可以每天进行完整备份,因为这也用不了多少时间,但当数据库很大时,就不太可能每天进行一次完整备份了,这时候就可以使用增量备份.增量备份的原理就是使用了mysql的binlog日志.本次操作的 ...

  4. NVME SSD vs SATA SSD(转)

    NVMe是个啥?未来SSD主流标准早知 关注固态硬盘的朋友应该对于这个词汇并不陌生,特别是今年NVMe也频繁出现在各大媒体文章中,随着高端SSD市场逐渐从SATA专项PCI-E时,以前的AHCI标准已 ...

  5. Java基础82 jsp中的EL表达式(网页知识)

    1.EL表达式的作用 EL表达式的作用:向浏览器输出域对象中的变量值或者表达式计算结果.语法:${变量或者表达式} 注: Jsp的核心语法:jsp的表达式<%= %>和jsp的脚本< ...

  6. 你竟然在公钥中下毒!——如何在RSA公钥中添加后门

    原文:http://www.hackdig.com/?01/hack-17893.htm 分享到: 当我知道它是如何运行时,我惊得下巴都掉了.这是一个非常简单的手法,但这篇文章会颠覆你之前对RSA的看 ...

  7. python之uinttest,用例执行顺序

    unittest单元测试框架, 以test开头的测试用例,默认执行顺序是按照ASC码来执行 如果有类,先排序执行类,在执行类中,再排序用例顺序执行 如果想要按照指定的顺序执行测试用例. 那么就需要用到 ...

  8. Rookey.Frame之实体FluentValidation验证

    昨天给大家介绍了Rookey.Frame框架的实体设计,今天继续跟大家分享实体的FluentValidation验证,在Rookey.Frame框架中可以设置多种验证方式:FluentValidati ...

  9. USACO 6.1 A Rectangular Barn

    A Rectangular Barn Mircea Pasoi -- 2003 Ever the capitalist, Farmer John wants to extend his milking ...

  10. 006 python的面向对象基础

    1.类 描述具有相同属性与方法的对象的集合. 2.创建类 使用class来创建一个新类,class之后为类的名称并以冒号结尾 3.程序 #!/usr/bin/python # -*- coding: ...