洛谷 P3224 永无乡
洛谷 P3224 永无乡
题意
给出 \(n\) 个点。有两种操作:
- 在点 \(x\) 和点 \(y\) 之间连一条边。
- 询问与 \(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;
}
本文来自博客园,作者:maniubi,转载请注明原文链接:https://www.cnblogs.com/maniubi/p/18393827,orz