ZOJ 3261 Connections in Galaxy War(逆向并查集)

参考链接:

   http://www.cppblog.com/yuan1028/archive/2011/02/13/139990.html

  http://blog.csdn.net/roney_win/article/details/9473225

题意:N个星球,编号从0到N-1。每个星球有一个战斗力power,且这N个星球之间建有一些通道,可以相互联系,在星球大战中,一些星球要向和自己联通的星球中power最强且大于自己的星球求救,且在星球大战中会有一些通道被损坏。

  两种操作:破坏a和b之间的通道;a星球该向谁求救。

逆向并查集:

  与并查集不同,给出一个图中原有的一些边,然后给出操作,操作不是向图中添加边,而是在已有的边上,将边删除。

  对于该种情况,需要首先读入所有操作,把要求删除的边全部删除,再按照从后往前的顺序处理操作,这样删边操作转化为了添边的操作。

 

思路:我们先输入所有数据,即所谓的离线输入,将星球大战之后的状态作为初始状态,进行并查集的操作,遇到destroy时,就恢复a到b之间的通道,那么就很容易维护根节点的性质了,这题就变得很简单了。

 

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>

using namespace std;

const int maxn=10010;
int father[maxn];
long long power[maxn];
int n,m,q;
int ans[maxn*5];  //存储最后要输出的答案

struct Edge{
    int u,v,flag;  //u、v表示边的端点,u<=v;flag=0表示改变被删除

    //将u从小到大排序,若u相同时,按v从小到大排序
    bool operator < (const Edge tmp)const {
        if(u==tmp.u)
            return v<tmp.v;
        return u<tmp.u;
    }
} edge[2*maxn];

//先把所有的询问都存储下来
struct  Query{
    int k,a,b; //k=1表示操作是询问,k=2表示操作是删边
}query[maxn*5];

struct Node {
    int u;  //u代表集合中具有最大能力值的点的编号
    long p; //p代表集合中点的最大能力值
} node[maxn];

void init() {
    for(int i=0; i<n; i++) {
        father[i]=i;
        node[i].u=i;
        node[i].p=power[i];
    }
}

int find_root(int x) {
    if(father[x]!=x)
       father[x]=find_root(father[x]);
    return father[x];
}

void Union(int x,int y) {
    father[y]=x;
    if(node[x].p<node[y].p){
        node[x].p=node[y].p;
        node[x].u=node[y].u;
    }
    else if(node[x].p==node[y].p && node[x].u>node[y].u){
        node[x].u=node[y].u;
    }
}
//二分查找边,a<=b
void findEdge(int a,int b){
    int mid,mins=0,maxs=m-1;
    while(mins<=maxs){
        mid=(mins+maxs)>>1;
        if(a==edge[mid].u && b==edge[mid].v){
            edge[mid].flag=0;
            return;
        }
        if(a<edge[mid].u){
            maxs=mid-1;
        }
        else if(a>edge[mid].u){
            mins=mid+1;
        }
        else{
            if(b<edge[mid].v){
                maxs=mid-1;
            }
            else{
                mins=mid+1;
            }
        }
    }
}
int main() {
    int a,b,blank=0;
    char ch[10];
    while(scanf("%d",&n)!=EOF) {
        memset(vis,0,sizeof(vis));
        if(blank==0)
            blank=1;
        else
            puts("");
        for(int i=0;i<n;i++){
            scanf("%I64d",&power[i]);
        }
        scanf("%d",&m);
        for(int i=0; i<m; i++) {
            scanf("%d%d",&a,&b);
            if(a<b) {
                edge[i].u=a;
                edge[i].v=b;
                edge[i].flag=1;
            } else {
                edge[i].u=b;
                edge[i].v=a;
                edge[i].flag=1;
            }
        }
        sort(edge,edge+m); //一开始忘记排序了
        scanf("%d",&q);
        for(int i=0; i<q; i++) {
            scanf("%s",ch);
            if(ch[0]=='q') {
                scanf("%d",&a);
                query[i].k=1;
                query[i].a=a;
                query[i].b=-1;
            }
            else{
                scanf("%d%d",&a,&b);
                int t;
                if(a>b){
                    t=a;a=b;b=t;
                }
                findEdge(a,b);
                query[i].k=2;
                query[i].a=a;
                query[i].b=b;
            }
        }
        int x,y;
        init();
        for(int i=0;i<m;i++){
            if(edge[i].flag==1){
                x=find_root(edge[i].u);
                y=find_root(edge[i].v);
                if(x!=y){
                    Union(x,y);
                }
            }
        }
        int u,v;
        for(int i=q-1;i>=0;i--){
            if(query[i].k==1){
                x=find_root(query[i].a);
                if(node[x].p>power[query[i].a]){
                    ans[i]=node[x].u;
                }
                else{
                    ans[i]=-1;
                }
            }
            else{
                u=query[i].a;
                v=query[i].b;
                x=find_root(u);
                y=find_root(v);
                if(x!=y){
                    Union(x,y);
                }
                ans[i]=-2;
            }
        }
        for(int i=0;i<q;i++){
            if(ans[i]==-2)
                continue;
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

 

 

 

posted @ 2013-09-05 15:55  辰曦~文若  阅读(429)  评论(2编辑  收藏  举报