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

题意:(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[N], power[N], 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值