【并查集】Connections in Galaxy War ZOJ - 3261
Connections in Galaxy War ZOJ - 3261
题意:
有\(n\)颗星星,编号\(0到n\)。第\(i\)颗星星的能量值为\(Pi\)。每颗星星可以向与它直接或间接相连、且能量值比它大(相等也不行)的星星求助,如果这样的星星有多颗,则向其中编号最小的星星求助。现给定\(m\)条星星之间的通道与\(q\)条指令,指令分两种:destroy:某条通道被摧毁;query:询问某颗星星的求助对象的编号。如果没有星星可求助,输出-1。
思路:
因为“直接或间接相连”这个条件,显然并查集可以做。但是并查集的合并过程中会压缩路径,使得删除某条路径时情况会变得非常复杂,显然不能顺着指令顺序来做。
所以我们先记录会被摧毁的通道,然后用最后仍然幸存的通道merge各个结点。接着反向遍历指令,遇到query就正常查询,遇到destroy就恢复这个通道。将答案全部入栈后再输出即可。
至于“编号最小”这一点,只要将通道u-v按u<v的原则储存,并且在find操作中将能量相同而编号更小的结点作为父节点即可。
const int maxn = 50000 + 100;
int fa[maxn];
LL power[maxn];
int n, m, q;
stack<int> s;
map< pair<int, int>, int> mp;
struct node {
char str[20];
int x, y;
}Q[maxn];
struct edge{
int u,v;
}e[maxn];
int find(int p) {
return fa[p] == p ? p : find(fa[p]);
}
void merge(int a, int b) {
int r1 = find(a);
int r2 = find(b);
if (r1 != r2) {
if (power[r1] > power[r2]) fa[r2] = r1;
else if (power[r2] > power[r1]) fa[r1] = r2;
//能量不同时,能量大的作父节点
else {
//能量相同时,编号小的作父节点
if (r1 > r2) fa[r1] = r2;
else fa[r2] = r1;
}
}
}
void init() {
while (!s.empty()) s.pop();
memset(Q, -1, sizeof(Q));
memset(power, 0, sizeof(power));
mp.clear();
for (int i = 0; i < maxn; i++) fa[i] = i;
}
void Read() {
for (int i = 0; i < n; i++) cin >> power[i];
cin >> m;
for (int i = 1; i <= m; i++) {
cin >> e[i].u >> e[i].v;
if (e[i].u > e[i].v) swap(e[i].u, e[i].v);
}
cin >> q;
for (int i = 1; i <= q; i++) {
cin >> Q[i].str;
if (Q[i].str[0] == 'q') cin >> Q[i].x;
else{
cin >> Q[i].x >> Q[i].y;
if (Q[i].x > Q[i].y) swap(Q[i].x, Q[i].y);
pair<int, int> P;
P = make_pair(Q[i].x, Q[i].y);
mp[P] = 1;
//标记不存在
}
}
}
void build() {
for (int i = 1; i <= m; i++) {
pair<int, int>P;
P = make_pair(e[i].u, e[i].v);
if (mp.count(P)) continue;
//已标记不存在,跳过
else merge(e[i].u, e[i].v);
}
}
void solve() {
for (int i = q; i >= 1; i--) {
if (Q[i].str[0] == 'q') {
int root = find(Q[i].x);
if (power[root] > power[Q[i].x]) s.push(root);
else s.push(-1);
}
else merge(Q[i].x, Q[i].y);
}
while (!s.empty()) {
cout << s.top() << endl;
s.pop();
}
}
int main()
{
//ios::sync_with_stdio(false);
int first = 1;
while (cin >> n) {
if (!first) cout << endl;
first = 0;
init();
Read();
build();
solve();
}
return 0;
}