[kuangbin带你飞]专题五 并查集 zoj3261(反向并查集+map记录要摧毁边)

Connections in Galaxy War

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路:

反向操作,宇宙从无开始。

  1. 先离线。
  2. 由于要反向,可以map记录哪条边要被破坏.
  3. 在读完数据后,把读入的边没被破坏的先建好,之后就开始反向操作,并做好记录。
  4. 并查集里的merge(由于要B的能量要大于A的能量,所以每次操作时把能量大的作为祖先,如果能量相同,那么就小号作为祖先)
  5. 之后开始反向询问,如果是destroy那么就建边,
  6. 否则就询问:查看 B(祖先的)能量和 A的能量(因为A可能和祖先B有相同的能量)p【B】> p【A】那么就可以救援,ans【i】=B;

反思

  1. 一开始每考虑到可能A和祖先相同能量,是救援不了的。
  2. 没考虑到可能读入数据(q次询问里的destory 和 m条边的顺序可能不同,记录可能有误差,所以把小的序号放前面)
  3. 多case里每个输出一个空格,由于是文件读写,所以可以这样。
	if(flag)flag=false;
        else printf("\n");
        For(i,1,q)if(!ans[i].flag)printf("%d\n",ans[i].out);
  1. map里可以用pair,使用时像这样。
	ans[i].a=a;ans[i].b=b;
            ma[mp(a,b)]=1;
  1. strcmp(s,t)当两串相等时,才放回0

AC

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#define mp make_pair
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
const int maxn=1e4+10;
typedef pair<int,int>pa;
struct Querry
{
    int a,b;
    bool flag;//true destory
    int out;
}ans[5*maxn];
map<pa,int>ma;
char s[1000];
int f[maxn],p[maxn],fr[2*maxn], to[2*maxn];
int n,m,q;
int find(int x)
{
    if(x==f[x])return x;
    return f[x]=find(f[x]);
}
void merge(int u,int v)
{
    int uf=find(u), rf=find(v);
    if(p[uf]>p[rf])f[rf]=uf;
    else if(p[uf]==p[rf])
    {
        if(uf<rf)f[rf]=uf;
        else if(uf>rf)f[uf]=rf;
    }
    else f[uf]=rf;
}
void init()
{
    For(i,0,n)f[i]=i;
    ma.clear();
   // ma.empty();
    For(i,0,n-1)scanf("%d", &p[i]);
    scanf("%d", &m);
    int a,b;
    For(i,1,m)
    {
        scanf("%d%d", &a,&b);
        if(a>b)swap(a,b);
        fr[i]=a,to[i]=b;
    }
  //  cout<<"ok"<<endl;
    scanf("%d", &q);
    For(i,1,q)
    {
        scanf("%s",s);
       // cout<<"ok"<<endl;
        if(strcmp(s,"query")==0)
        {
            scanf("%d",&ans[i].a);
            ans[i].flag=false;
        }
        else
        {
            scanf("%d%d", &a,&b);
            if(a>b)swap(a,b);
            ans[i].a=a;ans[i].b=b;
            ma[mp(a,b)]=1;
         //   printf("a=%d, b=%d, %d\n",a, b,ma[mp(a,b)]);
            ans[i].flag=true;
        }
    }
}
void build()
{
    For(i,1,m)
    {
        int id=ma[mp(fr[i],to[i])];
        if(!id)merge(fr[i],to[i]);
    }
}
void solve()
{
    for(int i=q; i>=1; i--)
    {
        if(ans[i].flag)merge(ans[i].a,ans[i].b);
        else
        {
            int fx=find(ans[i].a);
            if(p[ans[i].a]<p[fx])ans[i].out=fx;
            else ans[i].out=-1;
        }
    }
}
int main()
{
    bool flag=true;
    while(~scanf("%d", &n))
    {
        
        init();
        build();
     //   cout<<"ok"<<endl;
        solve();
        if(flag)flag=false;
        else printf("\n");
        For(i,1,q)if(!ans[i].flag)printf("%d\n",ans[i].out);
     //   printf("/n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值