【POJ2985】【Treap + 并查集】The k-th Largest Group

Description

Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to group some of the cats. To do that, he first offers a number to each of the cat (1, 2, 3, …, n). Then he occasionally combines the group cat i is in and the group cat j is in, thus creating a new group. On top of that, Newman wants to know the size of the k-th biggest group at any time. So, being a friend of Newman, can you help him?

Input

1st line: Two numbers N and M (1 ≤ NM ≤ 200,000), namely the number of cats and the number of operations.

2nd to (m + 1)-th line: In each line, there is number C specifying the kind of operation Newman wants to do. If C = 0, then there are two numbers i and j (1 ≤ ij ≤ n) following indicating Newman wants to combine the group containing the two cats (in case these two cats are in the same group, just do nothing); If C = 1, then there is only one number k (1 ≤ k ≤ the current number of groups) following indicating Newman wants to know the size of the k-th largest group.

Output

For every operation “1” in the input, output one number per line, specifying the size of the kth largest group.

Sample Input

10 10
0 1 2
1 4
0 3 4
1 2
0 5 6
1 1
0 7 8
1 1
0 9 10
1 1

Sample Output

1
2
2
2
2

Hint

When there are three numbers 2 and 2 and 1, the 2nd largest number is 2 and the 3rd largest number is 1.

Source

【分析】
这道题的正解是线段树,我只是拿来练个手而已。
写一遍直接交,狂T无压力....
Treap的常数实在是太大了,写了N遍,开始拿以为是内存池的问题.
尼玛开了内存池居然会比动态内存分配慢!!谁能告诉我为什么(╯‵□′)╯︵┻━┻。
好吧,关键不在这里...
treap写一般会t但是进行优化了以后还是可以过的。
只要不把大小为1的并查集加进去就可以了.........
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <vector>
  6 #include <utility>
  7 #include <iomanip>
  8 #include <string>
  9 #include <cmath>
 10 #include <queue>
 11 #include <assert.h>
 12 #include <map>
 13 #include <ctime>
 14 #include <cstdlib>
 15 
 16 const int N = 200000 + 10;
 17 const int SIZE = 250;//块状链表的大小 
 18 const int M = 50000 + 5;
 19 using namespace std;
 20 struct TREAP{
 21        struct Node{
 22               int fix, size;
 23               int val;
 24               Node *ch[2];
 25        }mem[N], *root;
 26        struct mem_poor{//内存池 
 27               queue<Node>Q;
 28               void push(Node *t){//消除指针t所占用的地址 
 29                    Q.push((*t)); 
 30               }
 31               Node* get(){
 32                    Node* t = &Q.front();
 33                    Q.pop();
 34                    return t;
 35               }
 36        }poor;
 37        int tot, size;
 38        //大随机
 39        void init(){
 40            // for (int i = 0; i <= 200000 + 5; i++)
 41             //poor.Q.push(mem[i]);
 42             size = 0;
 43             tot = 0;
 44        } 
 45        int BIG_RAND(){return rand();}
 46        Node *NEW(){
 47             Node *p = new Node;
 48             p->fix = rand();//BIG_RAND();
 49             p->size = 1;
 50             p->ch[0] = p->ch[1] = NULL;
 51             return p;
 52        }
 53        //将t的d节点换到t 
 54        void rotate(Node *&t, int d){
 55             Node *p = t->ch[d];
 56             t->ch[d] = p->ch[d ^ 1];
 57             p->ch[d ^ 1] = t;
 58             t->size = 1;
 59             if (t->ch[0] != NULL) t->size += t->ch[0]->size;
 60             if (t->ch[1] != NULL) t->size += t->ch[1]->size; 
 61             p->size = 1;
 62             if (p->ch[0] != NULL) p->size += p->ch[0]->size;
 63             if (p->ch[1] != NULL) p->size += p->ch[1]->size; 
 64             t = p;
 65             return; 
 66        }
 67        void insert(Node *&t, int val){
 68             //插入 
 69             if (t == NULL){
 70                t = NEW();
 71                t->val = val;
 72                //size++;
 73                return; 
 74             }
 75             //大的在右边,小的在左边 
 76             int dir = (val >= t->val);
 77             insert(t->ch[dir], val);
 78             //维护最大堆的性质 
 79             if (t->ch[dir]->fix > t->fix) rotate(t, dir);
 80             t->size = 1;
 81             if (t->ch[0] != NULL) t->size += t->ch[0]->size;
 82             if (t->ch[1] != NULL) t->size += t->ch[1]->size; 
 83        }
 84        //在t的子树中找到第k小的值 
 85        int kth(Node *t, int k){
 86            if (t == NULL ||  k<=0 || k > t -> size) return 1;
 87            if (t->size == 1 ) return t->val;
 88            int l = 0;//t的左子树中有多少值 
 89            if (t->ch[0] != NULL) l += t->ch[0]->size;
 90            if (k == (l + 1)) return t->val;
 91            if (k <= l) return kth(t->ch[0], k);
 92            else return kth(t->ch[1], k - (l + 1));
 93        }
 94        /*int find(Node *t, int val){
 95            if (t == NULL) return 0;
 96            int l = 0;//累加值
 97            if (t->ch[0] != NULL) l += t->ch[0]->size;
 98            if (val == t->val) return l + 1;
 99            else if (val < t->val) return find(t->ch[0], val);
100            else return l + 1 + find(t->ch[1], val);
101        }*/ 
102        //找到值为val的节点 
103        /*Node *&get(Node *&t, int val){
104            //if (t == NULL) return NULL;
105            if (val == t->val) return t;//根结点是,没办法 
106            
107            if (t->ch[0] != NULL && t->ch[0]->val == val) return t;
108            if (t->ch[1] != NULL && t->ch[1]->val == val) return t;
109            
110            if (val < t->val) return get(t->ch[0], val);
111            else return get(t->ch[1], val);
112        }*/
113        /*void update(Node *&t){
114             if (t == NULL) return;
115             update(t->ch[0]);
116             update(t->ch[1]);
117             t->size = 1;
118             if (t->ch[0] != NULL) t->size += t->ch[0]->size;
119             if (t->ch[1] != NULL) t->size += t->ch[1]->size; 
120        }*/
121        void Delete(Node* &t,int x){
122             int d;
123             if (x == t->val) d = -1;
124             else d = (x > t->val);
125             if (d == -1){
126                Node *tmp = t;
127                if(t->ch[0] == NULL){
128                   t = t->ch[1];
129                   //poor.push(tmp);
130                   delete tmp;
131                   tmp = NULL;
132                }else if(t->ch[1] == NULL){
133                   t = t->ch[0];
134                   //poor.push(tmp);
135                   delete tmp;
136                   tmp = NULL;
137                }else{
138                   int k = t->ch[0]->fix > t->ch[1]->fix ? 0 : 1;
139                   //int  k = 1; 
140                   rotate(t,k);
141                   Delete(t->ch[k ^ 1],x);
142                }
143             }else Delete(t->ch[d],x);
144             if (t!=NULL){
145                 t->size = 1;
146                 if (t->ch[0] != NULL) t->size += t->ch[0]->size;
147                 if (t->ch[1] != NULL) t->size += t->ch[1]->size; 
148             }
149        }
150        /*void print(Node *t){
151             if (t == NULL) return;
152             print(t->ch[0]);
153             printf("%d ", t->val);
154             print(t->ch[1]);
155        }*/
156 }treap; 
157 /*int Scan()  {  
158     int res = 0, ch, flag = 0;  
159     if((ch = getchar()) == '-')             //判断正负   
160         flag = 1;  
161     else if(ch >= '0' && ch <= '9')           //得到完整的数   
162         res = ch - '0';  
163     while((ch = getchar()) >= '0' && ch <= '9' )  
164         res = res * 10 + ch - '0'; 
165     return flag ? -res : res;  
166 }  */
167 int parent[N], n ,m;
168 int find(int x){return parent[x] < 0? x : parent[x] = find(parent[x]);}
169 
170 void init(){
171      treap.init();
172      treap.root = NULL;
173      //memset(parent, -1, sizeof(parent));
174      scanf("%d%d", &n, &m);
175      for (int i = 1; i <= n; i++) parent[i] = -1;
176      //n = Scan();
177      //m = Scan();
178      //for (int i = 1; i <= n; i++) treap.insert(treap.root, 1);
179 }
180 void work(){
181      for (int i = 1; i <= m; i++){
182          int t;
183          //t = Scan();
184          scanf("%d", &t);
185          if (t == 0){
186             int x, y;
187             scanf("%d%d", &x, &y);
188             //x = Scan();y = Scan();
189             x = find(x); 
190             y = find(y);
191             if (x == y) continue;
192             if (parent[x] < -1) treap.Delete(treap.root, -parent[x]);
193             if (parent[y] < -1) treap.Delete(treap.root, -parent[y]);
194             treap.insert(treap.root, -(parent[x] + parent[y]));
195             parent[y] += parent[x];
196             parent[x] = y;
197          }else{
198             int k;
199             scanf("%d", &k);
200             //k = Scan();i
201             if (treap.root == NULL || k > treap.root->size) {printf("1\n");continue;}
202             k = treap.root->size - k + 1;
203             printf("%d\n", treap.kth(treap.root, k));
204          }
205      }
206 }
207 
208 int main(){
209     int T;
210     srand(time(0));
211     #ifdef LOCAL
212     freopen("data.txt", "r", stdin);
213     freopen("out.txt", "w", stdout);
214     #endif
215     init();
216     work();
217     //debug();
218     return 0;
219 }
View Code

 

 

转载于:https://www.cnblogs.com/hoskey/p/4325918.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值