ZOJ 3261(逆向并查集)学了一手map+pair的用法

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261

借鉴了这位大佬的题意:https://www.cnblogs.com/cenariusxz/p/4792930.html

题意: 有很多颗星球,各自有武力值,星球间有一些联系通道,现在发生战争,有一些联系通道会被摧毁,而一些星球会通过还没有被摧毁的联系通道直接或者间接联系能够联系到的武力值最高的星球求救,如果有多个武力值都为最高的,那就联系一个编号最小的。现在给出一系列求救和摧毁的序列,一次执行,并对于每一个求救指令寻找合适的求救星球编号,如果没有可以求救的则输出 -1;
由于一般并查集只能够合并集合而不能将集合拆离,因此可以离线之后反向执行,这样集合的拆离就变成了集合的合并。

只要先保存所有的边和询问,然后标记所有的被摧毁的通道 ,然后扫一遍所有的联系通道关系,除了将会被摧毁的边不操作,将剩下的联系通道用并查集的方式建立起来。

由于需要查找的值是武力值最大并且编号最小的,所以可以在合并并查集选择武力值大的且编号小的作为祖先。

然后对于所有命令序列反向处理,从最后一条开始,查询就直接输出结果,如果查到的祖先节点是它自己就输出 -1,如果是摧毁通道那就建立这两点之间的通道就行了。

代码:

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;

#define mp(a,b) make_pair(a,b)
const int maxn =10000+5;

int N,p[maxn],M,Q,ans[maxn*5],fa[maxn],cnt;
char s[100];

map<pair<int,int>,int>edge;//记录边是否被摧毁

int find_(int x)
{
    return fa[x]==x? x: fa[x]=find_(fa[x]);
}

struct Edge
{
    int from,to;
} e[maxn*2];//所有的边

struct query
{
    int flag;
    int a,b;
    query()
    {
        b=0;
    }
} q[maxn*5];//查询

void unit(int x, int y)
{
    int u,v;
    u=find_(x);
    v=find_(y);
    if(u==v)
        return;
    if(p[u]>p[v])
    {
        fa[v]=u;
    }
    else if(p[u]<p[v])
    {
        fa[u]=v;
    }
    else if(p[u]==p[v])
    {
        if(u>v)
            fa[u]=v;
        else
            fa[v]=u;
    }
}

int main()
{
      int mk=0;
    while(scanf("%d",&N)!=EOF)
    {
        edge.clear();
        if(mk)
            printf("\n");
        mk=1;
        for(int i=0; i<N; i++)
        {
            scanf("%d",&p[i]);
            fa[i]=i;
        }
        scanf("%d",&M);
        int a,b;
        for(int i=0; i<M; i++)
        {
            scanf("%d%d",&a,&b);
            if(a>b)
                swap(a,b);
            e[i].from=a;
            e[i].to=b;
            edge[mp(a,b)]=1;
        }

        scanf("%d",&Q);

        for(int i=0; i<Q; i++)
        {
            scanf("\n%s ",s);
            if(s[0]=='q')
            {
                scanf("%d",&a);
                q[i].a=a;
                q[i].flag=0;
            }
            else if(s[0]=='d')
            {
                scanf("%d %d",&a,&b);
                if(a>b)
                    swap(a,b);
                q[i].a=a;
                q[i].b=b;
                q[i].flag=1;
                edge[mp(a,b)]=0;
            }
        }

        map<pair<int,int>,int>::iterator it;
        for(it=edge.begin(); it!=edge.end(); it++)
        {
            if(it->second)
            {
                pair<int,int> tmp=it->first;
                unit(tmp.first,tmp.second);
            }
        }

        cnt=Q;
        for(int i=Q-1; i>=0; i--)
        {
            if(q[i].flag==0)
            {
                cnt--;
                a=q[i].a;
                if(p[a]==p[find_(a)])
                    ans[cnt]=-1;
                else
                    ans[cnt]=find_(a);
            }
            else
            {
                a=q[i].a;
                b=q[i].b;
                unit(a,b);
            }
        }
        for(int i=cnt; i<Q; i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36300700/article/details/80092228
ZOJ