bzoj2733
并查集+treap+启发式合并
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cmath> 5 #include<ctime> 6 #include<iostream> 7 #include<algorithm> 8 #include<queue> 9 #include<stack> 10 #include<set> 11 #define rep(i,l,r) for(int i=(l);i<(r);i++) 12 #define clr(a,x) memset(a,x,sizeof(a)) 13 using namespace std; 14 typedef long long ll; 15 typedef pair<int,int> pii; 16 #define mkp(a,b) make_pair((a),(b)) 17 int read(){ 18 int ans=0,f=1; 19 char c=getchar(); 20 while(!isdigit(c)){ 21 if(c=='-') f=-1; 22 c=getchar(); 23 } 24 while(isdigit(c)){ 25 ans=ans*10+c-'0'; 26 c=getchar(); 27 } 28 return ans*f; 29 } 30 const int maxn=500009; 31 struct node{ 32 int s,v,p,r; 33 node*ch[2]; 34 void maintain(){ 35 s=ch[0]->s+ch[1]->s+1; 36 } 37 }; 38 node pool[maxn<<2],*root[maxn],*pt=pool,*null; 39 int n,m,q,p[maxn],f[maxn]; 40 node*newnode(int x,int cnt){ 41 pt->s=1;pt->v=x;pt->p=cnt;pt->r=rand(); 42 pt->ch[0]=pt->ch[1]=null; 43 return pt++; 44 } 45 int find(int x){ 46 return f[x]==x?f[x]:f[x]=find(f[x]); 47 } 48 void rot(node*&o,int d){ 49 node*t=o->ch[d^1]; 50 o->ch[d^1]=t->ch[d];t->ch[d]=o; 51 o->maintain();t->maintain(); 52 o=t; 53 } 54 void insert(node*&o,node*x){ 55 if(o==null){ 56 o=newnode(x->v,x->p); 57 }else if(x->v<o->v){ 58 insert(o->ch[0],x); 59 if(o->ch[0]->r>o->r) rot(o,1); 60 }else{ 61 insert(o->ch[1],x); 62 if(o->ch[1]->r>o->r) rot(o,0); 63 } 64 o->maintain(); 65 } 66 int query(node*o,int x){ 67 int t=o->ch[0]->s; 68 if(x==t+1) return o->p; 69 if(x<t+1) return query(o->ch[0],x); 70 return query(o->ch[1],x-t-1); 71 } 72 int X; 73 void join(node*o){ 74 if(o==null) return; 75 join(o->ch[0]); 76 insert(root[X],o); 77 join(o->ch[1]); 78 } 79 void merge(int x,int y){ 80 int u=find(x),v=find(y); 81 if(u==v) return; 82 if(root[u]->s<root[v]->s) swap(u,v); 83 f[v]=u; 84 X=u;join(root[v]); 85 } 86 void init(){ 87 null=newnode(0,0); 88 null->s=0;null->r=0; 89 rep(i,1,n+1) f[i]=i; 90 rep(i,1,n+1) root[i]=null; 91 } 92 int main(){ 93 n=read();m=read(); 94 init(); 95 rep(i,1,n+1){ 96 p[i]=read();p[i]=n-p[i]+1; 97 insert(root[i],newnode(p[i],i)); 98 } 99 rep(i,1,m+1){ 100 int from=read(),to=read(); 101 merge(from,to); 102 } 103 q=read(); 104 while(q--){ 105 char opt=getchar(); 106 while(opt!='Q'&&opt!='B') opt=getchar(); 107 int x=read(),y=read(); 108 if(opt=='Q') printf("%d\n",y>root[find(x)]->s?-1:query(root[find(x)],root[find(x)]->s-y+1)); 109 else merge(x,y); 110 } 111 return 0; 112 }
2733: [HNOI2012]永无乡
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1690 Solved: 891
[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
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
2
5
1
2