您的位置:首页 > 其它

ZOJ ~ 3261 ~ Connections in Galaxy War (逆序并查集 + map)

2018-01-16 21:49 393 查看
题意:星球大战,每个星球会有一个武力值,星球间有一些通道相连,直接或间接相连的星球可以互相求助(当然求助最厉害的星球啦)。先输入N表示有N个星球,编号为0~(n-1),然后输入M表示有M组关系,表示两个星球之间有通道。然后有Q次操作,操作有两种,

1.query a:问a能求助的最厉害的星球是哪个

2.destroy a b:a和b通道被摧毁了

对于每个query操作输出一个能求助到的最厉害的星球的编号,如果最厉害的有多个输出编号最小的那个,如果没有星球比他更厉害(即没有星球的武力值严格大于他)那么就输出-1。多组输出输出,每组数据后面输出一个空行,最后一组后面不输出空行。

思路:逆序并查集。由于并查集不能进行集合的拆离操作,所以逆向思考那么拆离操作就变成了合并操作。所以先进行离线操作,即把不会被摧毁的边都先建立起来,然后反向处理,合并的时候按武力值得大小合并,把小的合并到大的上,相同的时候把编号大的合并到编号小的上,把答案存到起来输出就可以了。

坑点:①a,b大小不一定,就是一开始告诉你1 2有关系,然后会有摧毁2 1的操作②格式控制,最后一行后面没有空行,其他都有

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
const int MAXQ = 50005;
int n, m, q;
struct Star
{
int power, pre;//武力值,父节点编号
}star[MAXN];//星球信息
struct in
{
int a, b;
char c;//操作
}in[MAXQ];//输入
int ans[MAXQ];//答案
map<pair<int, int>, bool> M;
int find(int x)
{
if (star[x].pre == x) return x;
star[x].pre = find(star[x].pre);
return star[x].pre;
}
void Union(int a, int b)
{
int root1 = find(a), root2 = find(b);
if (star[root1].power < star[root2].power) star[root1].pre = root2;
else if(star[root1].power > star[root2].power) star[root2].pre = root1;
else star[max(root1, root2)].pre = min(root1, root2);
}
int main()
{
bool has_out = false;
while (~scanf("%d", &n))
{
M.clear();
for (int i = 0; i < n; i++)
{
scanf("%d", &star[i].power);
star[i].pre = i;//初始化
}
scanf("%d", &m);
for (int i = 0; i < m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
M[make_pair(min(a, b), max(a, b))] = true;//需要建边
}
scanf("%d", &q);
string op;
for (int i = 0; i < q; i++)//操作保存到in
{
cin >> op;
in[i].c = op[0];
if (op[0] == 'q') scanf("%d", &in[i].a);
else if(op[0] == 'd')
{
scanf("%d%d", &in[i].a, &in[i].b);
M[make_pair(min(in[i].a, in[i].b), max(in[i].a, in[i].b))] = false;//被破坏的先不建边
}
}
//for (auto i: M) if (i.second) Union((i.first).first, (i.first).second);
for (map<pair<int, int>, bool>::iterator it = M.begin(); it != M.end(); it++)//建立关系
{
if ((*it).second) Union((*it).first.first, (*it).first.second);
}
int cnt = 0;
for (int i = q - 1; i >= 0; i--)//逆序处理操作
{
if (in[i].c == 'q')
{
int t = find(in[i].a);
if (star[t].power > star[in[i].a].power) ans[cnt++] = t;//可以求助即根节点武力值大于自己的武力值
else ans[cnt++] = -1;
}
else if(in[i].c == 'd') Union(in[i].a, in[i].b);//修复边
}
if(has_out) printf("\n");//格式控制
has_out = true;
for (int i = cnt - 1; i >= 0; i--) printf("%d\n", ans[i]);//输出答案
}
return 0;
}
/*
2
10 20
1
0 1
5
query 0
query 1
destroy 0 1
query 0
query 1

5
30 20 10 1 1
2
1 2
2 3
5
q 3
q 4
q 1
d 1 3
q 3
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: