BZOJ 1015 星球大战starwar

来源:互联网 发布:java解压缩gz文件 编辑:程序博客网 时间:2024/05/01 18:28

我存图用的邻接表,总觉得应该有更好的方法,无奈智商不够想不出来。

闲话少说,说一说我的步骤:(整体思路,离线、并查集)

    1.存图(邻接表),初始cnt为目前的连通块个数 n-k(当问题以外的点之间没有边,即他们每个点都是一个连通块),用que数组存第i个问题的点,用vis数组记录此点是第几个问题;

    2.先把问题里没有出现的点之间的边加进图中,更新cnt;

    3.从最后一个问题开始倒着循环,ans[i]表示未加入此时删除的点的连通块个数。把每个点关联的边加入图中,并判断如果这条边另一端的点j没有被删除(即vis[j]==0 || vis[i]<vis[j]),如果为真,更新cnt(cnt--),但由于连通快减少的个数总比满足条件的加入的边的个数少1,所以每次cnt还要加1;

    4.激动人心的时刻就要到了:输出ans数组,AC!


#include<stdio.h>#include<iostream>#include<algorithm>#include<string.h>#define MAXN 200010using namespace std;struct edge{    int to;    edge * p;} *ed[2*MAXN];int que[MAXN*2];int ans[MAXN*2];int f[MAXN*2];int vis[MAXN*2];void add(int a,int b){    edge * point=new edge;    point->to=b;    point->p=ed[a];    ed[a]=point;}int getf(int x){    return f[x]==x ? x : f[x]=getf(f[x]);}int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++){        int a,b;        scanf("%d%d",&a,&b);        add(a,b);        add(b,a);    }    int k;    memset(vis,0,sizeof(vis));    scanf("%d",&k);    for(int i=1;i<=k;i++){        scanf("%d",&que[i]);        vis[que[i]]=i;    }    int cnt=n-k;    for(int i=0;i<n;i++) f[i]=i;    for(int i=0;i<n;i++)        if(!vis[i])        for(edge* j=ed[i];j;j=j->p){            if(!vis[j->to] && getf(i)!=getf(j->to)){                f[getf(j->to)]=getf(i);                cnt--;            }        }       for(int i=k;i>=1;i--){        ans[i]=cnt;        for(edge* j=ed[que[i]];j;j=j->p){            int now=j->to;            if(getf(now)!=getf(que[i]) && (!vis[now] || vis[now]>vis[que[i]])){                f[getf(now)]=getf(que[i]);                cnt--;            }        }        cnt++;    }    ans[0]=cnt;    for(int i=0;i<=k;i++) printf("%d\n",ans[i]);    return 0;}


0 0
原创粉丝点击