HNOI2012 永无乡 无旋Treap
题目描述
永无乡包含 nnn 座岛,编号从 111 到 nnn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nnn 座岛排名,名次用 111 到 nnn 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 aaa 出发经过若干座(含 000 座)桥可以 到达岛 bbb ,则称岛 aaa 和岛 bbb 是连通的。
现在有两种操作:
B x y 表示在岛 xxx 与岛 yyy 之间修建一座新桥。
Q x k 表示询问当前与岛 xxx 连通的所有岛中第 kkk 重要的是哪座岛,即所有与岛 xxx 连通的岛中重要度排名第 kkk 小的岛是哪座,请你输出那个岛的编号。
输入输出格式
输入格式:第一行是用空格隔开的两个正整数 nnn 和 mmm ,分别表示岛的个数以及一开始存在的桥数。
接下来的一行是用空格隔开的 nnn 个数,依次描述从岛 111 到岛 nnn 的重要度排名。随后的 mmm 行每行是用空格隔开的两个正整数 aia_iai 和 bib_ibi ,表示一开始就存在一座连接岛 aia_iai 和岛 bib_ibi 的桥。
后面剩下的部分描述操作,该部分的第一行是一个正整数 qqq ,表示一共有 qqq 个操作,接下来的 qqq 行依次描述每个操作,操作的 格式如上所述,以大写字母 QQQ 或 BBB 开始,后面跟两个不超过 nnn 的正整数,字母与数字以及两个数字之间用空格隔开。
输出格式:对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 −1-1−1 。
输入输出样例
5 1 4 3 2 5 1 1 2 7 Q 3 2 Q 2 1 B 2 3 B 1 5 Q 2 1 Q 2 4 Q 2 3
-1 2 5 1 2
说明
对于 20% 的数据 n≤1000,q≤1000n \leq 1000, q \leq 1000n≤1000,q≤1000
对于 100% 的数据 n≤100000,m≤n,q≤300000n \leq 100000, m \leq n, q \leq 300000 n≤100000,m≤n,q≤300000
提交地址 : Luogu;
用并查集及维护, 无旋Treap直接启发式合并水过
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; #define inf 0x3f3f3f3f #define maxn 100010 int n, m; int rt[maxn], tot; struct fhq { int ch[2]; int val; int pri; int siz; }t[maxn]; int find(int x) { return x == rt[x] ? x : rt[x] = find(rt[x]); } void pushup(int o) { t[o].siz = t[t[o].ch[0]].siz + t[t[o].ch[1]].siz + 1; } void Split(int o, int k, int &x, int &y) { if(!o) x = y = 0; else { if(t[o].val <= k) { x = o; Split(t[o].ch[1], k, t[o].ch[1], y); } else { y = o; Split(t[o].ch[0], k, x, t[o].ch[0]); } pushup(o); } } int Merge(int x, int y) { if(!x || !y) return x + y; if(t[x].pri < t[y].pri) { t[x].ch[1] = Merge(t[x].ch[1], y); pushup(x); return x; } else { t[y].ch[0] = Merge(x, t[y].ch[0]); pushup(y); return y; } } void insert(int &root, int y) { int a, b; int v = t[y].val; Split(root, v, a, b); root =Merge(Merge(a, y), b); } void DFS(int x, int &y) { if(!x) return; DFS(t[x].ch[0], y); DFS(t[x].ch[1], y); t[x].ch[0] = t[x].ch[1] = 0; insert(y, x); } int HeBing(int x, int y) { if(t[x].siz > t[y].siz) swap(x, y); DFS(x, y); return y; } int K_th(int o, int k) { while(1) { if(k <= t[t[o].ch[0]].siz) { o = t[o].ch[0]; } else if(k == t[t[o].ch[0]].siz + 1) { return o; } else { k -= t[t[o].ch[0]].siz + 1; o = t[o].ch[1]; } } } int sz[maxn], old[maxn]; int main() { srand(987789213); cin >> n >> m; memset(old, -1, sizeof old); for(register int i = 1 ; i <= n ; i ++) { scanf("%d", &t[i].val); t[i].pri = rand(); t[i].siz = 1; rt[i] = i; old[t[i].val] = i; sz[i] = 1; } for(register int i = 1 ; i <= m ; i ++) { int a, b, c; scanf("%d%d", &a, &b); int fx = find(a), fy = find(b); if(fx == fy) continue; c = HeBing(rt[a], rt[b]); fx = find(a), fy = find(b); rt[fx] = rt[fy] = c; rt[c] = c; } int q; cin >> q; while(q--) { char ch; int x, y; int a, b, c; cin >> ch; scanf("%d%d", &x, &y); if(ch == 'Q') { int fx = find(x); printf("%d\n", old[t[K_th(rt[x], y)].val]); } else { int fx = find(x), fy = find(y); if(fx == fy) continue; c = HeBing(rt[x], rt[y]); fx = find(x), fy = find(y); rt[fx] = rt[fy] = c; rt[c] = c; } } return 0; }