您的位置:首页 > 其它

zoj 3261 - Connections in Galaxy War(并查集)

2013-10-25 17:52 429 查看
题意:(from:http://blog.csdn.net/ggggiqnypgjg/article/details/6621481)

    有n个星球,每个星球有一定的power值,某些星球是直接或间接相连的。。。当某个星球想求助时会找到相连的里面的power值最大而且大于自己的一个星球。。。先在给定这些power值并给定两两相连的信息,然后又q个操作,destroy a b是删除a b直接相连的边(保证存在),query
a求向谁求助,如果不能求助输出-1 。。。


思路:

    虽然并查集是不可逆的,但是我们可以离线处理,把删边变为填边,即把那些需要删掉的边一开始就不加进去,而是倒着处理那些操作,当碰到删边的时候我们再把要删的边加进去,这样并查集就很简单了,最后再把答案倒着输出就可以了。

代码如下:

const int N = 10005;
const int M = 20005;
const int Q = 50005;
map<pair<int, int>, int>fmap;
typedef pair<int,int>Pair;
typedef pair<pair<int,int>,int>Element;
struct Rec
{
int a, b;
}rec[M], que[Q];
int p
, power
, flag[M];
int find(int x) { return p[x]==x?x:p[x]=find(p[x]); }
void unionset(int a, int b)
{
int x = find(a);
int y = find(b);
if(x!=y&&power[x]<power[y]) p[x] = y;
if(x!=y&&power[x]>power[y]) p[y] = x;
if(x!=y&&power[x]==power[y]&&x>y) p[x] = y;
if(x!=y&&power[x]==power[y]&&x<y) p[y] = x;
}
int main()
{
int n, m, a, b, q, k = 0;
char tmp[20];
while(~scanf("%d", &n))
{
fmap.clear();
for(int i = 0; i < n; ++i) scanf("%d", &power[i]), p[i] = i;
scanf("%d", &m);
for(int i = 0; i < m; ++i)
{
scanf("%d%d", &a, &b);
if(a>b) swap(a,b);
Pair first(a,b);
Element element(first, i);
fmap.insert(element);
rec[i] = {a,b};
}
scanf("%d", &q);
memset(flag,0,sizeof(flag));
for(int i = 0; i < q; ++i)
{
scanf("\n%s", tmp);
if(tmp[0]=='q')
{
scanf("%d", &a);
que[i] = {-1,a};
}
else
{
scanf("%d%d", &a, &b);
if(a>b) swap(a,b);
Pair first(a,b);
int t = fmap[first];
flag[t] = 1;
que[i] = {a,b};
}
}
for(int i = 0; i < m; ++i)
if(!flag[i]) unionset(rec[i].a, rec[i].b);
int cnt = 0, ans[q], f;
for(int i = q-1; i >= 0; --i)
{
if(que[i].a!=-1) unionset(que[i].a, que[i].b);
else
{
f = find(que[i].b);
ans[cnt++] = power[f]==power[que[i].b]?-1:f;
}
}
if(k++) printf("\n");
for(int i = cnt-1; i >= 0; --i) printf("%d\n", ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: