【BZOJ 2733】【HNOI 2012】永无乡【treap启发式合并】
2017-03-17 21:22
417 查看
Description
永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。Input
输入文件第一行是用空格隔开的两个正整数 n 和 m,分别 表示岛的个数以及一开始存在的桥数。接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 ai 和 bi,表示一开始就存 在一座连接岛 ai 和岛 bi 的桥。后面剩下的部分描述操作,该部分的第一行是一个正整数 q, 表示一共有 q 个操作,接下来的 q 行依次描述每个操作,操作的格式如上所述,以大写字母 Q 或B 开始,后面跟两个不超过 n 的正整数,字母与数字以及两个数字之间用空格隔开。对于 20%的数据 n≤1000,q≤1000
对于 100%的数据 n≤100000,m≤n,q≤300000
题解
看到对第k大值得查询,就能想到treap,这道题是用treap的启发式合并。先用并查集维护集合,在合并treap时,将规模小的之间的元素一个一个插入规模大的里面。(至于复杂度什么的我也不会证,好像是O(n (log n)^2)
代码
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; #define N 100010 int f ,size ; int n,m,u,v,q; struct node{ node *ch[2]; int r,v,s; node(int x) { r = rand();v = x;ch[0] = ch[1] = NULL;s = 1;} int cmp(int x) { if(x == v) return -1; else return x > v ? 1 : 0; } void maintain() { s = 1; if(ch[0]) s += ch[0]->s; if(ch[1]) s += ch[1]->s; } }*root ; int find(int x){return x == f[x] ? x : f[x] = find(f[x]);} void rotate(node* &o,int d) { node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o; o->maintain();k->maintain(); o = k; } void insert(node* &o,int x) { if(o == NULL) o = new node(x); else { int d = o->cmp(x); insert(o->ch[d],x); if(o->ch[d]->r > o->r) rotate(o,d^1); } o->maintain(); } void del(node* &o,int fa) { if(o->ch[1]) del(o->ch[1],fa); if(o->ch[0]) del(o->ch[0],fa); insert(root[fa],o->v); delete(o); } void combine(int x,int y) { int fa = find(x),fb = find(y); if(size[fa] < size[fb]) swap(fa,fb); if(fa != fb) { f[fb] = fa; size[fa] += size[fb]; del(root[fb],fa); } } int kth(node* o,int k) { if(o == NULL || k <= 0 || k > o->s) return -1; int s = (o->ch[0]==NULL ? 0 : o->ch[0]->s); if(k == s + 1) return o->v; else if(k <= s) return kth(o->ch[0],k); else return kth(o->ch[1],k-s-1); } int k ; int main() { scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) { scanf("%d",&u); k[u] = i; insert(root[i],u); f[i] = i; size[i] = 1; } for(int i = 1;i <= m;i++) { scanf("%d%d",&u,&v); combine(u,v); } scanf("%d",&q); char str[3]; while(q--) { scanf("%s%d%d",str,&u,&v); if(str[0] == 'Q') { int fa = find(u); if(v > size[fa]) puts("-1\n"); else printf("%d\n",k[kth(root[fa],v)]); } if(str[0] == 'B') combine(u,v); } return 0; }
相关文章推荐
- BZOJ 2733([HNOI2012]永无乡-Treap启发式合并)
- 【BZOJ 2733】[HNOI2012]永无乡 启发式合并treap
- BZOJ 2733: [HNOI2012]永无乡 启发式合并treap
- BZOJ 2733 HNOI2012 永无乡 Treap+启发式合并
- BZOJ 2733: [HNOI2012]永无乡 (Treap+启发式合并)
- BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)
- bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)
- BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]
- BZOJ 2733 [HNOI2012] 永无乡 [splay+启发式合并做法]
- 【BZOJ 2733】【HNOI 2012】永无乡 Splay启发式合并
- BZOJ 2733 HNOI 2012 永无乡 平衡树启发式合并
- [并查集+启发式合并]BZOJ 2733——[HNOI2012]永无乡
- [BZOJ][平衡树+启发式合并][替罪羊树]2733: [HNOI2012]永无乡
- bzoj 2733 [HNOI2012]永无乡 splay启发式合并
- bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)
- BZOJ[2733][HNOI2012]永无乡 Splay启发式合并
- 【BZOJ 2733】 [HNOI2012]永无乡|Splay启发式合并
- 【模板】【bzoj2733】[HNOI2012]永无乡 Treap
- 【bzoj2733】[HNOI2012]永无乡 Treap启发式合并
- 【BZOJ】【P2733】【HNOI2012】【永无乡】【题解】【启发式合并】