BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

不难...treap + 启发式合并 + 并查集 搞搞就行了

----------------------------------------------------------------------------------------

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<iostream>

#define rep(i, n) for(int i = 0; i < n; ++i)

#define clr(x, c) memset(x, c, sizeof(x))

using namespace std;

const int maxn = 100000 + 5;

int p[maxn];

struct node *null, *pt;

struct node {

node* ch[2];

int v, s, r, x;

node(int _v = 0, int _x = 0) : v(_v), x(_x), s(1), r(rand()) {

ch[0] = ch[1] = null;

}

inline int cmp(int _v) {

if(v == _v) return -1;

return _v < v ? 0 : 1;

}

inline void maintain() {

s = ch[0]->s + ch[1]->s + 1;

}

void* operator new (size_t) { return pt++; }

};

node* root[maxn], N[maxn * 30];

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;

}

int x, v;

void insert(node* &o) {

if(o == null) o = new node(v, x);

else {

int d = v < o->v ? 0 : 1;

insert(o->ch[d]);

if(o->ch[d]->r > o->r) rotate(o, d ^ 1);

}

o->maintain();

}

void merge(node* &o, node* &O) {

if(o == null) return;

rep(i, 2) merge(o->ch[i], O);

x = o->x; v = o->v;

insert(O);

}

int kth(node* o, int k) {

int s = o->ch[0]->s;

if(k == s + 1) return o->x;

return k <= s ? kth(o->ch[0], k) : kth(o->ch[1], k - s - 1);

}

int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }

void init(int n) {

pt = N;

null = new(node);

rep(i, n) root[p[i] = i] = null;

null->s = 0;

}

void B(int u, int v) {

int x = find(u), y = find(v);

if(x != y) {

if(root[x]->s > root[y]->s) swap(x, y);

p[x] = y;

merge(root[x], root[y]);

}

}

int query(int x, int k) {

int X = find(x);

if(k > root[X]->s) return -1;

return kth(root[X], k);

}

int main() {

int n, m;

scanf("%d%d", &n, &m);

init(n);

rep(i, n) {

x = i + 1;

scanf("%d", &v);

insert(root[i]);

}

while(m--) {

int u, v;

scanf("%d%d", &u, &v);

B(u - 1, v - 1);

}

scanf("%d", &m);

while(m--) {

int u, v;

char op;

scanf(" %c%d%d", &op, &u, &v);

if(op == ‘B‘) B(u - 1, v - 1);

else printf("%d\n", query(u - 1, v));

}

return 0;

}

----------------------------------------------------------------------------------------

2733: [HNOI2012]永无乡

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1455  Solved: 771
[Submit][Status][Discuss]

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

Output

对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表 示所询问岛屿的编号。如果该岛屿不存在,则输出-1。

Sample Input

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

Sample Output

-1
2
5
1
2

HINT

Source

时间: 2024-10-26 16:03:43

BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)的相关文章

BZOJ 2733 HNOI2012 永无乡 Treap+启发式合并

题目大意:给定一个无向图以及n个点的排名,多次连接一条边,多次求某个点所在联通块中排名第k小的点的编号 初始对于每个点建立一棵只有一个节点的Treap,然后每次连接两个点,利用并查集找到两个点的根节点,将size较小的Treap暴力拆解插入大的中,然后将小的并查集合并到大的中 今天下午各种脑残,一个小小的Treap改了不下10遍0.0 快去喝脑白金0.0 #include<cstdio> #include<cstring> #include<iostream> #inc

BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2733 [题目大意] 给出n个点,每个点都有自己的重要度,现在有连边操作和查询操作, 查询操作要求找出一个连通块中重要度第k的点的id [题解] 我们用Treap维护每个连通块,对于连边操作,我们用启发式合并, 将size比较小的Treap并入size比较大的Treap,同时用并查集维护连通信息 [代码] #include <cstdio> #include <algorith

Bzoj 2733: [HNOI2012]永无乡 数组Splay+启发式合并

2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3955  Solved: 2112[Submit][Status][Discuss] Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达

bzoj 2733: [HNOI2012]永无乡 离线+主席树

2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1167  Solved: 607[Submit][Status] Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a

[BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k

bzoj 2733: [HNOI2012]永无乡

23333用并查集维护联通,然后网上搞splay就行啦. %高端splay写法(2333写在struct里了,是不是叫构造函数什么的??) 1 #include<bits/stdc++.h> 2 #define N 100005 3 #define LL long long 4 #define ls tr[x][0] 5 #define rs tr[x][1] 6 using namespace std; 7 inline int ra() 8 { 9 int x=0,f=1; char ch

【bzoj2733】[HNOI2012]永无乡 线段树合并

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k

BZOJ 2733 HNOI 2012 永无乡 平衡树启发式合并

题目大意:有一些岛屿,一开始由一些无向边连接.后来也有不断的无向边加入,每一个岛屿有个一独一无二的重要度,问任意时刻的与一个岛屿联通的所有岛中重要度第k大的岛的编号是什么. 思路:首先连通性一定要用并查集维护,然后就是联通快内的第k大问题,显然是平衡树.但是并查集的合并怎么搞?可以考虑按秩合并,这样的话就保证每次在平衡树中处理的元素尽量的少,就可以水过这个题了. 注意一下输出-1的判断. CODE: #include <map> #include <cstdio> #include

【BZOJ2733】永无乡[splay启发式合并or线段树合并]

题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被这坑了. 网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 这道题似乎挺经典的(至少我看许多神犇很早就做了这道题).这道题有两种写法:并查集+(splay启发式合并or线段树合并).我写的是线段树合并,因为--splay不会打+懒得学.