ZOJ - 3261 Connections in Galaxy War(离线+逆向并查集)

5 篇文章 0 订阅
1 篇文章 0 订阅

ZOJ - 3261
题意
这道并查集很有意思,一般的并查集都是加边,但它却是删边
当然啦,要是删边那还怎么用并查集来做呢?所以我们这里就要逆向思考,既然不会做删边,那就反着做加边
要反着做,那当然就不能一边输入一边处理了,所以要离线处理
(离线处理指当所有的数据输入结束后再开始处理)

代码附上:

#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
int n,m,q,a[N];
int fa[N];
struct node//需要连接的点的数据
{
    int c,d;
} link[N<<1];
struct query//查询的数据
{
    string ss;
    int cc,dd;
} qq[50010];
void init()//初始化
{
    for(int i=0; i<=n; ++i)
        fa[i]=i;
}
int fd_ys(int k)//合并压缩
{
    if(k!=fa[k])
        fa[k]=fd_ys(fa[k]);
    return fa[k];
}
void work(int c,int d)//点之间的处理
{
    int C=fd_ys(c);
    int D=fd_ys(d);
    if(C==D)
        return ;
    if(a[C]==a[D])
    {
        if(C<D)
            swap(C,D);
        fa[C]=D;
        return ;
    }
    if(a[C]>a[D])
        swap(C,D);
    fa[C]=D;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    bool cnt=0;
    while(cin>>n)
    {
        map<pair<int,int>,int>vis;//检查点与点能否连接
        stack<int>ans;
        init();
        for(int i=0; i<n; ++i)//每个点的值
            cin>>a[i];
        cin>>m;
        for(int i=0; i<m; ++i)//需要连接的每对点
            cin>>link[i].c>>link[i].d;
        cin>>q;
        for(int i=0; i<q; ++i)//查询
        {
            cin>>qq[i].ss;
            if(qq[i].ss=="query")
            {
                cin>>qq[i].cc;
                continue;
            }
            cin>>qq[i].cc>>qq[i].dd;
            vis[make_pair(qq[i].cc,qq[i].dd)]=1;//标记被破坏的每对点
            vis[make_pair(qq[i].dd,qq[i].cc)]=1;
        }
        for(int i=0; i<m; ++i)//除去被破坏的点,点与点之间连接
        {
            if(vis[make_pair(link[i].c,link[i].d)])
                continue;
            else
                work(link[i].c,link[i].d);
        }
        for(int i=q-1; i>=0; --i)
        {
            if(qq[i].ss=="query")//查询
            {
                fd_ys(qq[i].cc);
                if(a[fa[qq[i].cc]]==a[qq[i].cc])
                    ans.push(-1);
                else
                    ans.push(fa[qq[i].cc]);
            }
            else
                work(qq[i].cc,qq[i].dd);//连接
        }
        if(cnt)
            cout<<endl;//两组测试数据之间输出一个空行
        else
            cnt=1;
        while(ans.size())
        {
            cout<<ans.top()<<endl;//输出答案
            ans.pop();
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值