1. 程式人生 > >[POJ2985] [POJMonthly0608] The k-th Largest Group [並查集][樹狀陣列]

[POJ2985] [POJMonthly0608] The k-th Largest Group [並查集][樹狀陣列]

[ L i n k \frak{Link} ]


並查集+kth。。
套個權值樹狀陣列就可以。
把求k大轉化為求n-k+1小。
注意一開始有n

size1的集合,所以要先往bit_tree[1]上面加n

我居然把fa[fx]=fy寫成fa[fy]=fx(自閉

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cctype>
#include<cstdlib>
using namespace std;
int n, m, sum;
int fa[200005];
int siz[200005];
int tr[
200005]; void add(int x, int add) { while (x <= n) { tr[x] += add; x += x & -x; } } int query(int k) { int pos = 0, rnk = 0; for (int i = 20; i >= 0; --i) { pos |= 1 << i; if (pos >= n || rnk + tr[pos] >= k) { pos ^= 1 << i; } else { rnk += tr[pos]; } } return
pos + 1; } int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } void merge(int x, int y) { int fx = find(x); int fy = find(y); if (fx == fy) return; add(siz[fx], -1); add(siz[fy], -1); fa[fx] = fy; siz[fy] += siz[fx]; add(siz[fy], 1); --sum; } int main() { scanf("%d%d", &n, &m); sum = n; add(1, n); for (int i = 1; i <= n; ++i) { fa[i] = i; siz[i] = 1; } for (int c, j, k, i = 1; i <= m; ++i) { scanf("%d", &c); if (!c) { scanf("%d%d", &j, &k); merge(j, k); } else { scanf("%d", &k); printf("%d\n", query(sum - k + 1)); } } return 0; }