ZOJ 3261 Connections in Galaxy War(逆向处理)

本文解析了ZOJ3261竞赛题目,采用逆向处理的方法,通过查询和修复破坏的边来解决关于点权值的最大值查询问题。介绍了具体的实现思路和C++代码实现。

题目链接:
ZOJ 3261 Connections in Galaxy War
题意:
有n个点,每个点有权值,然后给出m条无向边。有两种操作:
query a.表示从a出发的能到达的所有点权值最大的点的编号(相同取编号最小,而且权值要比自己大)
如果存在这样的点输出最大权值,否则输出-1.
destory a,b 表示删除连接a,b的边
按照操作输入顺序,输出每次查询的结果。两个测试样例之间有空行。
分析:
主要是逆向处理。
把破坏的边从后往前依次先查询破坏后需要的查询然后修复这条边,直到查询结束。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxn=10010;
const int maxm=20010;
const int maxq=50010;

int n,m,q,u,v,aa,bb,in,root;
int dtot,qtot;
int val[maxn],vis[maxm],ans[maxn],pre[maxn];
//ans[i]表示i能连接的最大能量,根节点为能量最大的点,且多个最大权值时序号最小
char s[10];

struct Read{
    int a,b;
}read[maxm];

struct Des{
    int a,b,num;
}des[maxq];//保存破坏操作

struct Que{
    int a,num,ans;
}que[maxq];//保存查询操作

void init(int n)
{
    dtot=qtot=0;
    for(int i=0;i<n;i++)
    {
       pre[i]=i;
       ans[i]=val[i];
    }
}

int find(int x)
{
    if(pre[x]==x) return x;
    int tmp=find(pre[x]);
    ans[x]=max(ans[x],ans[pre[x]]);
    return pre[x]=tmp;
}

void mix(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy){//不在同一集合
        //if(ans[fx]>ans[fy]) //在fx集合可以找到更大能量
        if(val[fx]>val[fy])
        {//其实val[fx]和ans[fx]以及val[fy]和ans[fy]都是一样的
            pre[fy]=fx;
            ans[fy]=ans[fx];
        }
        else if(val[fx]==val[fy]&&fx<fy)
        {//最大能量一样但是fx下标更小
            pre[fy]=fx;
            ans[fy]=ans[fx];
        }
        else
        {
            pre[fx]=fy;
            ans[fx]=ans[fy];
        }
        //不会存在fx和fy的最大能量一样,而且最大能量的下标也一样,因为这样就有交集了,就是一个集合了
    }
}

int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
#endif // LOCAL
    int first=1;
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;i++)
            scanf("%d",&val[i]);
        init(n);
        memset(vis,0,sizeof(vis));
        scanf("%d",&m);
        for(int i=0;i<m;i++)
            scanf("%d%d",&read[i].a,&read[i].b);
        scanf("%d",&q);
        for(int i=0;i<q;i++)
        {
            scanf("%s",s);
            if(s[0]=='q')
            {
                scanf("%d",&u);
                que[qtot].a=u;
                que[qtot].num=i;
                qtot++;
            }
            else
            {
                scanf("%d%d",&u,&v);
                des[dtot].a=u;
                des[dtot].b=v;
                des[dtot].num=i;
                dtot++;
                for(int j=0;j<m;j++)//查找读入的边,将要破坏的边标记
                {
                    if(read[j].a==u&&read[j].b==v) vis[j]=1;
                    if(read[j].a==v&&read[j].b==u) vis[j]=1;
                }
            }
        }
        for(int i=0;i<m;i++)//将永不被破坏的边合并
        {
            if(vis[i]) continue;
            aa=read[i].a;
            bb=read[i].b;
            mix(aa,bb);
        }
        in=qtot-1;//最后一条查询语句编号
        for(int i=dtot-1;i>=0;i--)//对每条破坏语句,从后往前开始修复
        {
            while(que[in].num>des[i].num)//所有在这条破坏的路和在上一条已经修好的路之间的查询语句
            {
                //printf("que[index].num=%d\n",que[index].num);
                aa=que[in].a;
                if(val[find(aa)]==val[aa]) que[in].ans=-1;//如果能连接的最大能量和自身能量一样
                //两种情况:①本身即是根节点②根节点能量和自身一样但序号小
                else que[in].ans=find(aa);
                //printf("que[index].ans=%d\n",que[index].ans);
                in--;
            }
            aa=des[i].a;
            bb=des[i].b;
            mix(aa,bb);//修复
        }
        //在第一条破坏路径之前的查询语句,也就是所有路都不破坏时的查询
        while(in>-1)
        {
            aa=que[in].a;
            if(val[find(aa)]==val[aa]) que[in].ans=-1;
            else que[in].ans=find(aa);
            in--;
        }
        if(first) first=0;
        else printf("\n");
        for(int i=0;i<qtot;i++)
            printf("%d\n",que[i].ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值