P1197 [JSOI2008]星球大战

这道题跟猴子那道题差不多,挺简单的一个倒序并查集,变拆为建,把被毁的做标记,每个点可连的边也记录下来,先把能连的都连起来,然后从最后一个被毁的星球开始连可以连的边(指此时对方星球未被摧毁)作为下一个被毁星球重建的基础。细节比较多。

#include <iostream>
#include <cstdio>
#include <vector>
#define MA 400002
using namespace std;

int n,m,a[MA],b[MA],f[MA],t,star[MA],broken[MA],iis[MA],tot;
vector <int> son[200002];

int find(int x){
    if(f[x]!=x)    f[x]=find(f[x]);
    return f[x];
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a[i],&b[i]);
        son[a[i]].push_back(b[i]);
        son[b[i]].push_back(a[i]);
    }
    for(int i=0;i<n;i++)    f[i]=i;
    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        scanf("%d",&star[i]);
        broken[star[i]]=-1;
    }
    for(int i=1;i<=m;i++){
        int x=a[i],y=b[i];
        if(broken[x]==-1||broken[y]==-1)    continue;
        else{
            int fx=find(x);
            int fy=find(y);
            if(fx!=fy)    f[fx]=fy;
        }
    }
    for(int i=t;i>=1;i--){
        //printf("%d ",broken[2]);
        tot=0;
        for(int j=0;j<n;j++)
            if(f[j]==j&&broken[j]!=-1)    tot++;
        //cout<<endl;
        iis[i]=tot;
        for(int j=0;j<son[star[i]].size();j++){
            int x=star[i],y=son[star[i]][j];
            if(broken[y]==-1)    continue;
            //printf("%d %d\n",x,y);
            int fx=find(x);
            int fy=find(y);
            if(fx!=fy)    f[fx]=fy;
        }
        broken[star[i]]=0;
    }
    tot=0;
    for(int i=0;i<n;i++)
        if(f[i]==i)    tot++;
    iis[0]=tot;
    for(int i=0;i<=t;i++)
        printf("%d\n",iis[i]);
    return 0;
}
View Code

这是我最初的代码,想着每次干完之后都求一次目前有多少f【i】=i的,结果tle了一大堆。

#include <iostream>
#include <cstdio>
#include <vector>
#define MA 400002
using namespace std;

int n,m,a[MA],b[MA],f[MA],t,star[MA],broken[MA],iis[MA],tot;
vector <int> son[400002];

int find(int x){
    if(f[x]!=x)    f[x]=find(f[x]);
    return f[x];
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a[i],&b[i]);
        son[a[i]].push_back(b[i]);
        son[b[i]].push_back(a[i]);
    }
    for(int i=0;i<n;i++)    f[i]=i;
    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        scanf("%d",&star[i]);
        broken[star[i]]=-1;
    }
    tot=n-t;
    for(int i=1;i<=m;i++){
        int x=a[i],y=b[i];
        if(broken[x]==-1||broken[y]==-1)    continue;
        else{
            int fx=find(x);
            int fy=find(y);
            if(fx!=fy){
                f[fx]=fy;
                tot--;
            }    
        }
    }
    iis[t+1]=tot;
    for(int i=t;i>=1;i--){
        //printf("%d ",broken[2]);
        tot++;
        //cout<<endl;
        broken[star[i]]=0;
        for(int j=0;j<son[star[i]].size();j++){
            int x=star[i],y=son[star[i]][j];
            if(broken[y]==-1)    continue;
            //printf("%d %d\n",x,y);
            int fx=find(x);
            int fy=find(y);
            if(fx!=fy){
                f[fy]=fx;
                tot--;
            }    
        }
        iis[i]=tot;
    }
    for(int i=1;i<=t+1;i++)
        printf("%d\n",iis[i]);
    return 0;
}
View Code

后来看了看题解,有位大神非常厉害,初始tot计数为n-t(即未被摧毁的所有城市)合并时可以合并就-1,每一个被摧毁的星球重建tot就++,可以和对方星球合并就再-1,见识了见识了。

 

posted @ 2019-07-16 17:19  sdzmq  阅读(165)  评论(0编辑  收藏  举报