POJ--2985(树状数组 / Treap +并查集)

2015-03-16 19:52:57

思路:一道比较裸的插入不断插入数值、删除数值 + 查询第k大的题目。

  (1)对于合并操作,可以采用并查集来维护,并维护一个num值来表示group总数。

  (2)对于查询第k大的操作

    (i)可以用树状数组维护+二分查找来不断逼近第k大

    (ii)可以利用树状数组本身c[]数组的特性来倍增逼近第k大

    (iii)用treap来查询第k大

    (iv)当然还可以用线段树.....

方法1:树状数组+二分

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <string>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define MEM(a,b) memset(a,b,sizeof(a))
16 #define REP(i,n) for(int i=1;i<=(n);++i)
17 #define REV(i,n) for(int i=(n);i>=1;--i)
18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i)
20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
21 #define MP(a,b) make_pair(a,b)
22 
23 typedef long long ll;
24 typedef pair<int,int> pii;
25 const int INF = (1 << 30) - 1;
26 const int MAXN = 300010;
27 
28 int N,M,num;
29 int fa[MAXN],sz[MAXN];
30 
31 struct BIT{
32     int c[MAXN];
33     int Lowbit(int x){
34         return x & (-x);
35     }
36     void clear(){
37         MEM(c,0);
38     }
39     void Update(int x,int d){
40         while(x <= N){
41             c[x] += d;
42             x += Lowbit(x);
43         }
44     }
45     int Getsum(int x){
46         int res = 0;
47         while(x){
48             res += c[x];
49             x -= Lowbit(x);
50         }
51         return res;
52     }
53 }bt;
54 
55 int Find(int x){
56     return fa[x] == x ? x : fa[x] = Find(fa[x]);
57 }
58 
59 int main(){
60     int a,b,c,k;
61     scanf("%d%d",&N,&M);
62     bt.Update(1,N);
63     REP(i,N) fa[i] = i,sz[i] = 1;
64     num = N;
65     REP(i,M){
66         scanf("%d",&c);
67         if(c == 0){
68             scanf("%d%d",&a,&b);
69             int x = Find(a);
70             int y = Find(b);
71             if(x == y) continue;
72             bt.Update(sz[x],-1);
73             bt.Update(sz[y],-1);
74             fa[x] = y;
75             sz[y] += sz[x];
76             bt.Update(sz[y],1);
77             num--;
78         }
79         else{
80             scanf("%d",&k);
81             k = num + 1 - k;
82             int l = 1,r = N;
83             while(l <= r){
84                 int mid = (l + r) / 2; //getmid(l,r);
85                 if(bt.Getsum(mid) >= k) r = mid - 1;
86                 else l = mid + 1;
87             }
88             printf("%d\n",l);
89         }
90     }
91     return 0;
92 }
View Code

 

方法2:树状数组

  这个方法很奇妙,用到了c[]数组本身的倍增特性,哎,果然要善于发现数据结构的潜力才行~

  首先,我们知道 c [a] 保存的是 arr[a-lowbit(a)+1] + arr[a-lowbit(a)+2] + .... + arr[a] 这个和。

  假设最终第k大的group大小为ans,那么c[ans] >= k,将ans二进制拆分为2^p1 + 2^p2 + ... + 2^pm

  那么,c[ans] = c[2^p1] + c[2^p2] + ... + c[2^pm],那么我们只要倒序枚举2的幂来找出p1~pm的值就行。

  【 如:for(int i = MAX_LOG; i >= 0; --i) , 2的幂为(1 << i) 】 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <string>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define MEM(a,b) memset(a,b,sizeof(a))
16 #define REP(i,n) for(int i=1;i<=(n);++i)
17 #define REV(i,n) for(int i=(n);i>=1;--i)
18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i)
20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
21 #define MP(a,b) make_pair(a,b)
22 
23 typedef long long ll;
24 typedef pair<int,int> pii;
25 const int INF = (1 << 30) - 1;
26 const int MAXN = 200010;
27 const int MAX_LOG = log(MAXN) / log(2);
28 
29 int N,M,num;
30 int fa[MAXN],sz[MAXN];
31 
32 struct BIT{
33     int c[MAXN];
34     void clear(){ MEM(c,0); }
35     int Lowbit(int x){ return x & (-x); }
36     void Update(int x,int d){
37         while(x <= N){
38             c[x] += d;
39             x += Lowbit(x);
40         }
41     }
42     int Getsum(int x){
43         int res = 0;
44         while(x){
45             res += c[x];
46             x -= Lowbit(x);
47         }
48         return res;
49     }
50 }bt;
51 
52 int Find(int x){ return fa[x] == x ? x : fa[x] = Find(fa[x]); }
53 void Union(int a,int b){
54     int x = Find(a),y = Find(b);
55     if(x != y){
56         bt.Update(sz[x],-1);
57         bt.Update(sz[y],-1);
58         fa[x] = y;
59         sz[y] += sz[x];
60         bt.Update(sz[y],1);
61         num--;
62     }
63 }
64 
65 int Find_kth(int k){
66     int res = 0,cnt = 0;
67     for(int i = MAX_LOG; i >= 0; --i){
68         res += (1 << i);
69         if(res > N || cnt + bt.c[res] >= k) res -= (1 << i);
70         else cnt += bt.c[res];
71     }
72     return res + 1;
73 }
74 
75 int main(){
76     int a,b,c,k;
77     while(scanf("%d%d",&N,&M) != EOF){
78         bt.clear();
79         bt.Update(1,N);
80         num = N;
81         REP(i,N) fa[i] = i,sz[i] = 1;
82         while(M--){
83             scanf("%d",&c);
84             if(c == 0){
85                 scanf("%d%d",&a,&b);
86                 Union(a,b);
87             }
88             else{
89                 scanf("%d",&k);
90                 k = num + 1 - k;
91                 printf("%d\n",Find_kth(k));
92             }
93         }
94     }
95     return 0;
96 }
View Code

 

方法3:Treap

  这题是treap的启蒙题。

  用treap来维护group大小的值,并且记录相同的值的个数,还要记录下以每个节点为根的子树的节点总数,然后就是在二叉搜索树上面找第k大了。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <vector>
  6 #include <map>
  7 #include <set>
  8 #include <stack>
  9 #include <queue>
 10 #include <string>
 11 #include <iostream>
 12 #include <algorithm>
 13 using namespace std;
 14 
 15 #define MEM(a,b) memset(a,b,sizeof(a))
 16 #define REP(i,n) for(int i=1;i<=(n);++i)
 17 #define REV(i,n) for(int i=(n);i>=1;--i)
 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i)
 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
 21 #define MP(a,b) make_pair(a,b)
 22 
 23 typedef long long ll;
 24 typedef pair<int,int> pii;
 25 const int INF = (1 << 30) - 1;
 26 const int MAXN = 200010;
 27 
 28 int N,M,num;
 29 int fa[MAXN],sz[MAXN];
 30 
 31 struct Treap{
 32     int root,tcnt;
 33     int key[MAXN],pro[MAXN],cnt[MAXN],sz[MAXN],son[MAXN][2];
 34     void clear(){
 35         root = 0;
 36         tcnt = 0;
 37         pro[0] = INF;
 38         sz[0] = 0;
 39     }
 40     void Update(int x){
 41         sz[x] = cnt[x] + sz[son[x][0]] + sz[son[x][1]];
 42     }
 43     void Rotate(int &x,int t){
 44         int y = son[x][t];
 45         son[x][t] = son[y][1 - t];
 46         son[y][1 - t] = x;
 47         Update(x);
 48         Update(y);
 49         x = y;
 50     }
 51     void _Insert(int &x,int k){
 52         if(x){
 53             if(key[x] == k) ++cnt[x];
 54             else{
 55                 int t = k > key[x];
 56                 _Insert(son[x][t],k);
 57                 if(pro[son[x][t]] < pro[x]) Rotate(x,t);
 58             }
 59         }
 60         else{
 61             x = ++tcnt;
 62             key[x] = k;
 63             cnt[x] = 1;
 64             pro[x] = rand(); //随机化优先级
 65             son[x][0] = son[x][1] = 0;
 66         }
 67         Update(x);
 68     }
 69     void _Erase(int &x,int k){
 70         if(key[x] == k){
 71             if(cnt[x] > 1) cnt[x]--;
 72             else{
 73                 if(son[x][0] == 0 && son[x][1] == 0){
 74                     x = 0;
 75                     return;
 76                 }
 77                 int t = pro[son[x][0]] > pro[son[x][1]];
 78                 //没有左儿子t = 1 , 没有右儿子t = 0
 79                 Rotate(x,t);
 80                 _Erase(x,k);
 81             }
 82         }
 83         else    _Erase(son[x][k > key[x]],k);
 84         Update(x);
 85     }
 86     int _Get_kth(int &x,int k){
 87         if(k <= sz[son[x][0]])
 88             return _Get_kth(son[x][0],k);
 89         k -= sz[son[x][0]] + cnt[x];
 90         if(k <= 0) return key[x];
 91         return _Get_kth(son[x][1],k);
 92     }
 93     void Insert(int k){
 94         _Insert(root,k);
 95     }
 96     void Erase(int k){
 97         _Erase(root,k);
 98     }
 99     int Get_kth(int k){
100         return _Get_kth(root,k);
101     }
102 }tp;
103 
104 int Find(int x){
105     return fa[x] == x ? x : fa[x] = Find(fa[x]);
106 }
107 
108 void Union(int a,int b){
109     int x = Find(a),y = Find(b);
110     if(x != y){
111         tp.Erase(sz[x]);
112         tp.Erase(sz[y]);
113         fa[x] = y;
114         sz[y] += sz[x];
115         tp.Insert(sz[y]);
116         num--;
117     }
118 }
119 
120 int main(){
121     int a,b,c,k;
122     scanf("%d%d",&N,&M);    
123     tp.clear();
124     REP(i,N) fa[i] = i,sz[i] = 1,tp.Insert(1);
125     num = N;
126     while(M--){
127         scanf("%d",&c);
128         if(c == 0){
129             scanf("%d%d",&a,&b);
130             Union(a,b);
131         }
132         else{
133             scanf("%d",&k);
134             k = num + 1 - k;
135             printf("%d\n",tp.Get_kth(k));
136         }
137     }
138     return 0;
139 }
View Code

 

posted @ 2015-03-16 21:17  Naturain  阅读(175)  评论(0编辑  收藏  举报