POJ 2985 名次树
题意:1~n个猫,有合并操作,有询问操作,合并两只猫所在的集合,询问第K大的集合。
分析:合并操作用并查集,用size维护,询问操作用Treap。注意优化,不能刚开始就把所有size = 1放到名次树中,是1的不做处理,而是不够的时候返回一个1;
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 7 struct Node { 8 Node *ch[2]; 9 int r; 10 int v; 11 int s; 12 Node(int v):v(v) {ch[0]=ch[1] = NULL;r=rand();s=1;} 13 bool operator < (const Node& rhs) const { 14 return r < rhs.r; 15 } 16 17 int cmp(int x) const { 18 if(x==v) return -1; 19 return x < v ? 0 : 1; 20 } 21 22 void maintain() { 23 s = 1; 24 if(ch[0]!=NULL) s+=ch[0]->s; 25 if(ch[1]!=NULL) s+=ch[1]->s; 26 } 27 28 }*root; 29 30 void rotate(Node* &o,int d) 31 { 32 Node *k=o->ch[d^1]; 33 o->ch[d^1]=k->ch[d]; 34 k->ch[d]=o; 35 o->maintain(); 36 k->maintain(); 37 o=k; 38 } 39 void insert(Node* &o,int v)//可插入重复值 40 { 41 if(o==NULL) o=new Node(v); 42 else 43 { 44 int d=v < o->v? 0:1; 45 insert(o->ch[d],v); 46 if(o->ch[d]->r > o->r) 47 rotate(o,d^1); 48 } 49 o->maintain(); 50 } 51 void remove(Node* &o,int v) 52 { 53 int d=o->cmp(v); 54 if(d==-1) 55 { 56 Node *u=o; 57 if(o->ch[0] && o->ch[1]) 58 { 59 int d2= o->ch[0]->r < o->ch[1]->r ?0:1; 60 rotate(o,d2); 61 remove(o->ch[d2],v); 62 } 63 else 64 { 65 if(o->ch[0]==NULL) o=o->ch[1]; 66 else o=o->ch[0]; 67 delete u; 68 } 69 } 70 else remove(o->ch[d],v); 71 if(o) o->maintain(); 72 } 73 74 75 int kth(Node *o,int k)//返回第k大的值,不是第k小 76 { 77 if(o==NULL || k<=0 || k> o->s) return 1; 78 int s = (o->ch[1]==NULL)?0:o->ch[1]->s; 79 if(k==s+1) return o->v; 80 else if(k<=s) return kth(o->ch[1],k); 81 else return kth(o->ch[0],k-s-1); 82 } 83 84 const int maxn=200000+1000; 85 int n,m; 86 int father[maxn],size[maxn]; 87 88 89 int Find_Set(int x) { 90 if(father[x]!=x) 91 father[x] = Find_Set(father[x]); 92 return father[x]; 93 } 94 95 int main() 96 { 97 //freopen("in.txt","r",stdin); 98 root = NULL; 99 for(int i=0;i<maxn;i++) { 100 father[i] = i; 101 size[i] = 1; 102 } 103 scanf("%d%d",&n,&m); 104 //for(int i=0;i<n;i++) 105 //insert(root,1); 106 while(m--) { 107 int cmp; 108 scanf("%d",&cmp); 109 if(cmp==0) { 110 int u,v; 111 scanf("%d%d",&u,&v); 112 int fx = Find_Set(u); 113 int fy = Find_Set(v); 114 if(fx!=fy) 115 { 116 if(size[fx]!=1) remove(root,size[fx]); 117 if(size[fy]!=1) remove(root,size[fy]); 118 father[fy] = fx; 119 size[fx]+=size[fy]; 120 insert(root,size[fx]); 121 } 122 } 123 else { 124 int k; 125 scanf("%d",&k); 126 printf("%d\n",kth(root,k)); 127 } 128 } 129 130 131 return 0; 132 }