题面

永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 \(1\) 到 \(n\) 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 \(a\) 出发经过若干座(含 \(0\) 座)桥可以 到达岛 \(b\) ,则称岛 \(a\) 和岛 \(b\) 是连通的。

现在有两种操作:

B x y 表示在岛 \(x\) 与岛 \(y\) 之间修建一座新桥。

Q x k 表示询问当前与岛 \(x\) 连通的所有岛中第 \(k\) 重要的是哪座岛,即所有与岛 \(x\) 连通的岛中重要度排名第 \(k\) 小的岛是哪座,请你输出那个岛的编号。

题解

为什么我的\(splay\)这么慢?

线段树合并好像可以做

不过练练平衡树合并也行

合并时启发式合并

复杂度\(O(nlog^2n)\)

Code

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 100010;
  4. struct node {
  5. int ch[2], v, f, s, id;
  6. }t[N*30];
  7. int root[N], tot;
  8. void pushup(int x) {
  9. t[x].s = t[t[x].ch[0]].s + t[t[x].ch[1]].s + 1;
  10. }
  11. void rotate(int x) {
  12. int y = t[x].f, z = t[y].f, k = t[y].ch[1] == x;
  13. t[z].ch[t[z].ch[1] == y] = x; t[x].f = z;
  14. t[y].ch[k] = t[x].ch[k^1]; t[t[x].ch[k^1]].f = y;
  15. t[y].f = x; t[x].ch[k^1] = y;
  16. pushup(y);
  17. }
  18. void splay(int x, int goal, int k) {
  19. while (t[x].f != goal) {
  20. int y = t[x].f, z = t[y].f;
  21. if (z != goal)
  22. (t[y].ch[1] == x) ^ (t[z].ch[1] == y) ? rotate(x) : rotate(y);
  23. rotate(x);
  24. }
  25. pushup(x);
  26. if (!goal) root[k] = x;
  27. }
  28. void insert(int k, int x, int id) {
  29. int now = root[k], f = 0;
  30. while (now) f = now, now = t[now].ch[x > t[now].v];
  31. now = ++tot;
  32. t[f].ch[x > t[f].v] = now;
  33. t[now].f = f; t[now].v = x; t[now].id = id;
  34. splay(now, 0, k);
  35. }
  36. int kth(int k, int x) {
  37. int now = root[k];
  38. while (1) {
  39. int ls = t[now].ch[0], rs = t[now].ch[1];
  40. if (t[ls].s >= x) now = ls;
  41. else if (t[ls].s + 1 < x) now = rs, x -= (t[ls].s + 1);
  42. else return t[now].id;
  43. }
  44. }
  45. int n, m;
  46. int fa[N], a[N];
  47. int find(int x) {
  48. return x == fa[x] ? x : fa[x] = find(fa[x]);
  49. }
  50. void dfs(int x, int y) {
  51. insert(x, t[y].v, t[y].id);
  52. if (t[y].ch[0]) dfs(x, t[y].ch[0]);
  53. if (t[y].ch[1]) dfs(x, t[y].ch[1]);
  54. return ;
  55. }
  56. void merge(int a, int b) {
  57. if (a == b) return ;
  58. if (t[root[a]].s < t[root[b]].s) swap(a, b);
  59. fa[b] = a;
  60. dfs(a, root[b]);
  61. }
  62. void deb(int x) {
  63. if (t[x].ch[0]) deb(t[x].ch[0]);
  64. printf("%d ", t[x].v);
  65. if (t[x].ch[1]) deb(t[x].ch[1]);
  66. }
  67. int main() {
  68. scanf("%d%d", &n, &m);
  69. for (int i = 1; i <= n; i++) fa[i] = i, scanf("%d", &a[i]);
  70. for (int i = 1; i <= m; i++) {
  71. int x, y;
  72. scanf("%d%d", &x, &y);
  73. x = find(x), y = find(y);
  74. fa[y] = x;
  75. }
  76. for (int i = 1; i <= n; i++) {
  77. int x = find(i);
  78. insert(x, a[i], i);
  79. }
  80. int Q;
  81. scanf("%d", &Q);
  82. while (Q--) {
  83. char c; int a, b;
  84. cin >> c >> a >> b;
  85. if (c == 'Q') {
  86. a = find(a);
  87. /*printf("test : ");
  88. deb(root[a]);
  89. printf("\n");*/
  90. if (t[root[a]].s < b) puts("-1");
  91. else printf("%d\n", kth(a, b));
  92. }
  93. else {
  94. a = find(a), b = find(b);
  95. merge(a, b);
  96. }
  97. }
  98. return 0;
  99. }

洛谷 P3224 [HNOI2012]永无乡的更多相关文章

  1. 洛谷 P3224 [HNOI2012]永无乡 解题报告

    P3224 [HNOI2012]永无乡 题目描述 永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 ...

  2. 洛谷P3224 [HNOI2012]永无乡(线段树合并+并查集)

    题目描述 永无乡包含 nnn 座岛,编号从 111 到 nnn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nnn 座岛排名,名次用 111 到 nnn 来表示.某些岛之间由巨大的桥连接, ...

  3. [洛谷P3224][HNOI2012]永无乡

    题目大意:给你$n$个点,每个点有权值$k$,现有两种操作: 1. $B\;x\;y:$将$x,y$所在联通块合并2. $Q\;x\;k:$查询第$x$个点所在联通块权值第$k$小是哪个数 题解:线段 ...

  4. 2018.08.11 洛谷P3224 [HNOI2012]永无乡(线段树合并)

    传送门 给出n个带点权的点,支持连边和查询连通块第k大. 这个貌似就是一道线段树合并的裸板啊... 代码: #include<bits/stdc++.h> #define N 100005 ...

  5. 【洛谷P3224】永无乡 并查集+Splay启发式合并

    题目大意:给定 N 个点的图,点有点权,初始有一些无向边,现在有 Q 个询问,每个询问支持动态增加一条无向边连接两个不连通的点和查询第 X 个点所在的联通块中权值第 K 大的是哪个点. 题解:学会了平 ...

  6. 洛谷.3224.[HNOI2012]永无乡(Splay启发式合并)

    题目链接 查找排名为k的数用平衡树 合并时用启发式合并,把size小的树上的所有节点插入到size大的树中,每个节点最多需要O(logn)时间 并查集维护连通关系即可 O(nlogn*insert t ...

  7. 线段树合并+并查集 || BZOJ 2733: [HNOI2012]永无乡 || Luogu P3224 [HNOI2012]永无乡

    题面:P3224 [HNOI2012]永无乡 题解: 随便写写 代码: #include<cstdio> #include<cstring> #include<iostr ...

  8. P3224 [HNOI2012]永无乡 题解

    P3224 [HNOI2012]永无乡 题解 题意概括 有若干集合,每个集合最初包含一个值,和一个编号1~n.两个操作:合并两个集合,查询包含值x的集合中第k大值最初的集合编号. 思路 维护集合之间关 ...

  9. bzoj2733 / P3224 [HNOI2012]永无乡(并查集+线段树合并)

    [HNOI2012]永无乡 每个联通块的点集用动态开点线段树维护 并查集维护图 合并时把线段树也合并就好了. #include<iostream> #include<cstdio&g ...

随机推荐

  1. [C++] static member variable and static const member variable

    static member variable[可读可写] 可以通过指针间接修改变量的值 static const member variable[只读] 压根就不可以修改变量的值,会报错

  2. strlen头文件

    #include <string.h> 函数strlen strsep 等等

  3. input框添加阴影效果

    .input:hover,.input:focus{ border:1px solid #85afe1; -webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0 ...

  4. 【微服务架构】SpringCloud之Hystrix断路器(六)

    一:什么是Hystrix 在分布式环境中,许多服务依赖项中的一些将不可避免地失败.Hystrix是一个库,通过添加延迟容差和容错逻辑来帮助您控制这些分布式服务之间的交互.Hystrix通过隔离服务之间 ...

  5. CodeSmith Generator 6.5 自动生成后的源码分析

    1,NetTiers代码结构流程分析: 2,CodeSmithNetTiers使用实践总结 参看流程结构图和实体定义文件关系图,可以看出自动代码生成后,若是手工来调,还是很麻烦的.鉴于此,建议:1,若 ...

  6. oracle数据库sqlldr命令的使用

    将数据导入 oracle 的方法应该很多 , 对于不同需求有不同的导入方式 , 最近使用oracle的sqlldr命令 导入数据库数据感觉是个挺不错的技术点 .  使用sqlldr命令 将文本文件导入 ...

  7. Windows安装mysql8.0

    一.下载并解压 地址:https://dev.mysql.com/downloads/mysql/ 如下图: 下载解压后 二.创建my.ini文件 在D:\mysql\mysql-8.0.13-win ...

  8. leetcode 从排序数组中删除重复项

    最近的学习是相当的无聊,并且很无趣,每天都浪费了很多时间,比如今天下午,就是搞一手成语接龙,我也是醉了- 并且我也不知道学什么了,所以决定刷题 虽然我是0算法基础,0逻辑能力的渣渣,但是尽力每天做一道 ...

  9. Android应用开发以及设计思想深度剖析

    Android应用开发以及设计思想深度剖析(1) 21cnbao.blog.51cto.com/109393/956049

  10. Ubuntu16.04中把默认JAVA设置为Oracle的JDK!

    系统当中已经存在了OpenJDK,默认的JDK是它,并不是Oracle的JDK,执行下面操作就可以把Oracle的JDK设置为默认的了! 首先假设我们已经把Oracle的JDK安装和配置好了,但是就是 ...