[POJ2985] [POJMonthly0608] The k-th Largest Group [并查集][树状数组]

[ L i n k \frak{Link} ]


并查集+kth。。
套个权值树状数组就可以。
把求k大转化为求n-k+1小。
注意一开始有nsize1的集合,所以要先往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;
}

猜你喜欢

转载自blog.csdn.net/Estia_/article/details/83817448