其他分享
首页 > 其他分享> > Luogu P1197 [JSOI2008]星球大战

Luogu P1197 [JSOI2008]星球大战

作者:互联网

经巨佬们指教,得知要用:逆向思维法(这个一定要想到啊QwQwQ)

之后想了想,发现我大致思路跟第一篇题解比较像(后来AC代码的细节不一样,我是在每次‘恢复’循环开始时计数的,题解是循环末尾,大同小异吧)

但我在每次计数的写法上调了好长时间

最初想的是每次枚举每个结点看是否fa[i]==i,后来才知道肯定会超时

但我不知道我这种做法为什么除了TLE 以外还全WA了,也许是什么东西打错了?懒散的我就没有深究了QwQ(未解之谜QwQ)

因为TLE,我就立刻看了题解,改进方法

其实这个计数完全可以O(n)

计数核心思想:

计数相关语句已用//标出。

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

int n,m,k,cnt,fa[400005],head[400005],at[400005],ans[400005];

int tot;

bool vis[400005];

struct edge{
    int u,v,next;
    bool exit;
}e[1000005];

inline void add(int u,int v){
    e[++cnt].v=v;
    e[cnt].u=u;
    e[cnt].next=head[u];
    head[u]=cnt;
}

inline int getfa(int v){
    if(fa[v]==v)return v;
    fa[v]=getfa(fa[v]);
    return fa[v];
}

inline void merge(int x,int y){
    int fx=getfa(x),fy=getfa(y);
    if(fx!=fy)tot--,fa[fx]=fy;//
}

int main(){
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    scanf("%d",&k);
    for(int i=1;i<=k;i++){
        scanf("%d",&at[i]);
        vis[at[i]]=1;
    }
    tot=n-k;//
    for(int i=1;i<=cnt;i++){
        if(!vis[e[i].u]&&!vis[e[i].v]){
            merge(e[i].u,e[i].v);
        }
    }
    for(int i=k;i>=1;i--){
        ans[i]=tot++;//
        vis[at[i]]=0;
        for(int j=head[at[i]];j!=-1;j=e[j].next){
            if(!vis[e[j].v])merge(at[i],e[j].v);
        }
    }
    ans[0]=tot;//
    for(int i=0;i<=k;i++){
        printf("%d\n",ans[i]);
    }
}

标签:head,int,Luogu,JSOI2008,cnt,400005,fa,include,P1197
来源: https://www.cnblogs.com/Y15BeTa/p/11323103.html