【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

POJ Monthly--2006.08.27, zcgzcgzcg

【分析】

这道题的正解是线段树,我只是拿来练个手而已。

写一遍直接交,狂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 }

时间: 2024-10-29 04:56:13

【POJ2985】【Treap + 并查集】The k-th Largest Group的相关文章

BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2733 [题目大意] 给出n个点,每个点都有自己的重要度,现在有连边操作和查询操作, 查询操作要求找出一个连通块中重要度第k的点的id [题解] 我们用Treap维护每个连通块,对于连边操作,我们用启发式合并, 将size比较小的Treap并入size比较大的Treap,同时用并查集维护连通信息 [代码] #include <cstdio> #include <algorith

POJ2985 The k-th Largest Group[树状数组求第k大值 并查集]

The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8807   Accepted: 2875 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 g

BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

不难...treap + 启发式合并 + 并查集 搞搞就行了 ---------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep(i, n) for(int i = 0; i &l

【bzoj1604】[Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 并查集+Treap/STL-set

题目描述 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l≤Xi,Yi≤[1..10^9]:Xi,Yi∈整数.当满足下列两个条件之一,两只奶牛i和j是属于同一个群的: 1.两只奶牛的曼哈顿距离不超过C(1≤C≤10^9),即lXi - xil+IYi - Yil≤C. 2.两只奶牛有共同的邻居.即,存在一只奶牛k,使i与k,j与k均同属一个群. 给出奶牛们的位置,请计算

POJ 2985 The k-th Largest Group(树状数组 并查集/查找第k大的数)

传送门 The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8690   Accepted: 2847 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants

CodeForces 745C Hongcow Builds A Nation 并查集

题意: 给了你n个城市 m条边 k个政府 每个政府管辖的区域内不能和其他政府的区域有相连 即政府之间不存在路径 问你在维护这种关系的同时 最多再加多少条边 思路: 先找出来每个联通块 再找出来没有归属的孤立的点 把他们都放到最大的联通块里 然后每个联通块之间的点两两连边是n*(n-1)/2条边 最后算出来的ans-m就好了 (看别人的博客学了一个max_element 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a

并查集应用

题目描述: One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls

【bzoj3674】 可持久化并查集加强版

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 (题目链接) 题意 维护并查集3个操作:合并:回到完成第k个操作后的状态:查询. Solution 其实就是用主席树的叶子节点维护并查集的可持久化数组fa[]. 细节 终于认识到了按秩合并的强大,单纯写个路径压缩Re飞,写了路径压缩+按秩合并比单纯的按秩合并每快多少→_→ 代码 // bzoj3674 #include<algorithm> #include<iostream>

BZOJ1015[JSOI2008]星球大战starwar[并查集]

1015: [JSOI2008]星球大战starwar Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 5253  Solved: 2395[Submit][Status][Discuss] Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重