2733: [HNOI2012]永无乡
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 3219 Solved: 1706
[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
用并查集维护连通性,再用Treap维护第k大
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <cstdlib>
#include <queue>
#include <stack>
#include <set>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (20161119)
#define ALL(x) (x).begin(),(x).end()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int>
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pri(a,n) for(int i=1;i<n;i++) cout<<a[i]<<' ';cout<<a[n]<<endl;
typedef long long ll;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
#define MAXN (100000*4)
int n,m;
struct treap{
ll rnd[MAXN],v[MAXN],w[MAXN];
int size[MAXN],l[MAXN],r[MAXN],cnt;
void mem() {
MEM(size) MEM(rnd) MEM(l) MEM(r) MEM(v) MEM(w)
cnt=0;
}
void update(int x)
{
size[x]=size[l[x]]+size[r[x]]+w[x];
}
void rturn(int &k)
{
int t=l[k];l[k]=r[t];r[t]=k;update(k);update(t);k=t;
}
void lturn(int &k)
{
int t=r[k];r[k]=l[t];l[t]=k;update(k);update(t);k=t;
}
void insert(int &x,ll rank,int y=0)
{
if(!x)
{
if (y) {
x=y;
l[x]=r[x]=0;
rnd[x]=rand();
size[x]=w[x]; return;
}
x=++cnt;
v[x]=rank; l[x]=r[x]=0;
rnd[x]=rand();size[x]=w[x]=1;
return ;
}
size[x]++;
if(v[x]<rank)
{
insert(r[x],rank,y);
if(rnd[r[x]]<rnd[x])lturn(x);
}
else if (v[x]>rank)
{
insert(l[x],rank,y);
if(rnd[l[x]]<rnd[x]) rturn(x);
}else w[x]++ ;
}
void unite(int &x,int y) {
if (!y) return ;
unite(x,l[y]);
unite(x,r[y]);
Rep(i,w[y]) insert(x,v[y],y);
}
void del(int &x,ll val) {
if (!x) return ;
if (v[x]==val) {
if (w[x]>1) {--w[x]; --size[x]; return; }
if (!l[x]||!r[x]) x=l[x]+r[x];
else if (rnd[l[x]]<rnd[r[x]]) rturn(x),del(x,val);
else lturn(x),del(x,val);
}
else {
--size[x];
if (val<v[x]) del(l[x],val); else del(r[x],val);
}
}
// return the pointer
int lower_bound(int x,ll rank) {
int ans=-1;
if (!x) return ans;
if (v[x]<=rank) {
ans=lower_bound(r[x],rank);
if (ans==-1) ans=x;
} else ans=lower_bound(l[x],rank);
return ans;
}
int upper_bound(int x,ll rank) {
int ans=-1;
if (!x) return ans;
if (v[x]>rank) {
ans=upper_bound(l[x],rank);
if (ans==-1) ans=x;
} else ans=upper_bound(r[x],rank);
return ans;
}
void pri(int x){
if (l[x]) pri(l[x]);
cout<<v[x]<<' ';
if (r[x]) pri(r[x]);
}
int get_rank(int x,ll val) {
if (!x) return 0;
if (v[x]==val) return size[l[x]]+1;
else if (val<v[x]) return get_rank(l[x],val);
else return get_rank(r[x],val)+size[l[x]]+w[x];
}
int how_many_number_lower_than_x(int x,ll val) {
if (!x) return 0;
if (v[x]==val) return size[l[x]];
else if (val<v[x]) return how_many_number_lower_than_x(l[x],val);
else return how_many_number_lower_than_x(r[x],val)+size[l[x]]+w[x];
}
int get_kth(int x,int k) {
if (!x) return -1;
if (k<=size[l[x]]) return get_kth(l[x],k);
else if (k<=size[l[x]]+w[x]) return x;
else return get_kth(r[x],k-size[l[x]]-w[x]);
}
}T;
int root[MAXN];
class bingchaji
{
public:
int father[MAXN],n,cnt,sz[MAXN];
void mem(int _n)
{
n=cnt=_n;
For(i,n) father[i]=i,sz[i]=1;
}
int getfather(int x)
{
if (father[x]==x) return x;
return father[x]=getfather(father[x]);
}
void unite(int x,int y)
{
x=getfather(x);
y=getfather(y);
if (x^y) {
--cnt;
if (sz[x]>sz[y]) swap(x,y);
father[x]=y;
sz[y]+=sz[x];
T.unite(root[y],root[x]);
}
}
bool same(int x,int y)
{
return getfather(x)==getfather(y);
}
}S;
int a[MAXN];
int main() {
// freopen("bzoj2733.in","r",stdin);
n=read();m=read();
S.mem(n);
For(i,n) a[i]=read(),T.insert(root[i],a[i]);
For(i,m) {
int x=read(),y=read();
S.unite(x,y);
}
int q=read();
For(i,q) {
char opt[10];scanf("%s",opt);
int x=read(),y=read();
switch (opt[0]) {
case 'B':S.unite(x,y);break;
case 'Q':printf("%d\n",T.get_kth(root[S.getfather(x)],y));
}
}
return 0;
}