洛谷 P3224 永无乡

洛谷 P3224 永无乡

题意

给出 \(n\) 个点。有两种操作:

  1. 在点 \(x\) 和点 \(y\) 之间连一条边。
  2. 询问与 \(x\) 联通的点中点权第 \(k\) 小的点。

思路

使用并查集维护连通性。每个联通块用一棵平衡树维护点权,合并时启发式合并。

时间复杂度:\(O(n \log^2n)\)

代码

#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
const int N = 1e5 + 5;
__gnu_pbds::tree<int, __gnu_pbds::null_type, less<int>,
__gnu_pbds::rb_tree_tag,
__gnu_pbds::tree_order_statistics_node_update> S[N];
int n, m;
int p[N], q[N], fa[N], Q;
int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
	int fx = find(x), fy = find(y);
	if (fx == fy) return ;
	if (S[fx].size() > S[fy].size()) 
		swap(fx, fy);
	for (auto num : S[fx]) 
		S[fy].insert(num);
	S[fx].clear();
	fa[fx] = fy;
}
int query(int x, int y) {
	int id = find(x);
	if (S[id].size() < y) return -1;
	return q[*S[id].find_by_order(y - 1)];
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m; 
	for (int i = 1; i <= n; i ++) {
		cin >> p[i];
		q[p[i]] = i, fa[i] = i;
		S[i].insert(p[i]);
	}
	for (int i = 1, u, v; i <= m; i ++) {
		cin >> u >> v;
		merge(u, v);
	}
	cin >> Q;
	string op; int x, y;
	while (Q --) {
		cin >> op >> x >> y;
		if (op == "B") {
			merge(x, y);
		} else cout << query(x, y) << "\n";
	}
	return 0;
}
posted @ 2024-09-03 07:41  maniubi  阅读(4)  评论(0编辑  收藏  举报