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 }
View Code

2733: [HNOI2012]永无乡

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

-1
2
5
1
2

HINT

 

Source

 
[Submit][Status][Discuss]
posted @ 2015-11-18 17:36  ChenThree  阅读(148)  评论(0编辑  收藏  举报