题面

永无乡包含 \(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

#include<bits/stdc++.h>
using namespace std; const int N = 100010; struct node {
int ch[2], v, f, s, id;
}t[N*30];
int root[N], tot; void pushup(int x) {
t[x].s = t[t[x].ch[0]].s + t[t[x].ch[1]].s + 1;
} void rotate(int x) {
int y = t[x].f, z = t[y].f, k = t[y].ch[1] == x;
t[z].ch[t[z].ch[1] == y] = x; t[x].f = z;
t[y].ch[k] = t[x].ch[k^1]; t[t[x].ch[k^1]].f = y;
t[y].f = x; t[x].ch[k^1] = y;
pushup(y);
} void splay(int x, int goal, int k) {
while (t[x].f != goal) {
int y = t[x].f, z = t[y].f;
if (z != goal)
(t[y].ch[1] == x) ^ (t[z].ch[1] == y) ? rotate(x) : rotate(y);
rotate(x);
}
pushup(x);
if (!goal) root[k] = x;
} void insert(int k, int x, int id) {
int now = root[k], f = 0;
while (now) f = now, now = t[now].ch[x > t[now].v];
now = ++tot;
t[f].ch[x > t[f].v] = now;
t[now].f = f; t[now].v = x; t[now].id = id;
splay(now, 0, k);
} int kth(int k, int x) {
int now = root[k];
while (1) {
int ls = t[now].ch[0], rs = t[now].ch[1];
if (t[ls].s >= x) now = ls;
else if (t[ls].s + 1 < x) now = rs, x -= (t[ls].s + 1);
else return t[now].id;
}
} int n, m;
int fa[N], a[N];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
} void dfs(int x, int y) {
insert(x, t[y].v, t[y].id);
if (t[y].ch[0]) dfs(x, t[y].ch[0]);
if (t[y].ch[1]) dfs(x, t[y].ch[1]);
return ;
} void merge(int a, int b) {
if (a == b) return ;
if (t[root[a]].s < t[root[b]].s) swap(a, b);
fa[b] = a;
dfs(a, root[b]);
} void deb(int x) {
if (t[x].ch[0]) deb(t[x].ch[0]);
printf("%d ", t[x].v);
if (t[x].ch[1]) deb(t[x].ch[1]);
} int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) fa[i] = i, scanf("%d", &a[i]);
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
x = find(x), y = find(y);
fa[y] = x;
}
for (int i = 1; i <= n; i++) {
int x = find(i);
insert(x, a[i], i);
}
int Q;
scanf("%d", &Q);
while (Q--) {
char c; int a, b;
cin >> c >> a >> b;
if (c == 'Q') {
a = find(a);
/*printf("test : ");
deb(root[a]);
printf("\n");*/
if (t[root[a]].s < b) puts("-1");
else printf("%d\n", kth(a, b));
}
else {
a = find(a), b = find(b);
merge(a, b);
}
}
return 0;
}

洛谷 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. leetCode--towSum

    题目链接:https://leetcode.com/problems/two-sum/description/ 此题的意思是:给定一个target值,从给定的数组中找两个数,使得这两个数的和==tar ...

  2. 给你的LINUX程序加个文字画LOGO

    经常看到很多的程序尤其LINUX程序有文字对应的那种LOGO,好酷炫啊. 研究了好久试了各种方法,后来在GOOGLE中搜索到一个软件叫:figlet 下载地址:http://www.figlet.or ...

  3. JS中立即执行函数的理解

    1.匿名函数不能单独定义,必须进行赋值操作或者立即执行,否则会被JS引擎定义为语法错误 function(){alert(dada);} VM229:1 Uncaught SyntaxError: U ...

  4. yii2 Html::a

    Html::a($text,$url = null,$options = []) $url 可以直接是字符串 // An empty string. This will return the curr ...

  5. InteliJ中文乱码;IDE快捷键使用

    启动服务器的时候出现如图 解决方法: 对服务器的位置进行编辑 增加如图的信息 -Dfile.encoding=UTF-8

  6. 编写高质量代码改善C#程序的157个建议——建议110:用类来代替enum

    建议110:用类来代替enum 枚举(enum)用来表示一组固定的值.例如,为了表示星期信息,我们可以定义枚举Week: enum Week { Monday, Tuesday, Wednesday, ...

  7. ZookeeperGettingStarted

    reference url:  http://zookeeper.apache.org/doc/trunk/zookeeperStarted.html#sc_FileManagement ZooKee ...

  8. python抓网页数据【ref:http://www.1point3acres.com/bbs/thread-83337-1-1.html】

    前言:数据科学越来越火了,网页是数据很大的一个来源.最近很多人问怎么抓网页数据,据我所知,常见的编程语言(C++,java,python)都可以实现抓网页数据,甚至很多统计\计算的语言(R,Matla ...

  9. log4net 入门使用

    log4net 是dotnet平台下的一个日记记录组件. 一  NuGet中安装log4net包: 二 配置log4net.config文件 配置文件内容: <?xml version=&quo ...

  10. Android-广播发送与接收(Java代码中订阅)

    Android四大组件之一广播,使用的也比较多,广播可大致分为两种,一种是Android系统区域的广播,是由系统指令发出,例如:点亮屏幕广播,开机过程中的一些广播 省略…, 然而还有一种广播就是我们自 ...