Luogu P1197 [JSOI2008]星球大戰

題外話:node

說真的這是一道不寫篇博客都對不起我半天debug的時間c++

真的順手太可怕了數組


正着刪點而後每次判聯通的複雜度仍是很高的,顯然不是這麼作的spa

這個時候咱們須要逆向思惟(√debug

考慮從最終狀態出發,將刪點變成增長點,好像複雜度要低了那麼一點點(大概是一大點點吧日誌

利用一個標記數組判斷當前點是否尚未被加入圖中,首先利用並查集計算最終狀態的連通塊個數,code

而後倒序向圖中加點:get

首先先把某個點扔進圖中,ans++;博客

而後對這個點的全部邊進行一波操做,判斷是否是會和其餘的連通塊一塊兒(並查集),變成大聯通塊(ans--)it

最後倒序輸出就行了

是離線作法?

CODE:

#include<bits/stdc++.h>

using namespace std;

inline int read(){
    int ans=0;
    char last=' ',ch=getchar();
    while(ch>'9'||ch<'0') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int mxn=400010;

int n,m,k;
int ans,p[mxn],P,fa[mxn];
bool bj[mxn];
int K[mxn];
struct node {
    int to,nxt;
}e[mxn<<1];
int head[mxn],ecnt;
void add(int from,int to) {
    ++ecnt;
    e[ecnt].nxt=head[from];
    head[from]=ecnt;
    e[ecnt].to=to;
}

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

int main() {
    n=read();
    m=read();
    for(int i=1,x,y;i<=m;i++) {
        x=read();
        x++;
        y=read();
        y++;
        add(x,y);
        add(y,x);
    }
    k=read();
    for(int i=1,a;i<=k;i++) {
        a=read();
        K[i]=++a;
        bj[K[i]]=1;
    }
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=n;i++) {
        if(bj[i]) continue;
        for(int j=head[i],v;j;j=e[j].nxt) {
            v=e[j].to;
            if(bj[v]) continue;
            int u=find(v);
            int I=find(i);
            if(u!=I)
                fa[u]=I;
        }
    }
    for(int i=1;i<=n;i++) 
        if(bj[i]==0&&fa[i]==i) ans++;
    p[++P]=ans;
    for(int i=k;i>=1;i--) {
        bj[K[i]]=0;ans++;
        for(int j=head[K[i]],v;j;j=e[j].nxt) {
            v=e[j].to;
            if(bj[v]==1) continue;
            int u=find(v);
            int z=find(K[i]);
            if(u!=z) {
                ans--;
                fa[u]=z;
            }
        }
        p[++P]=ans;
    }
    for(int i=P;i>=1;i--) 
        printf("%d\n",p[i]);
    return 0;
}

debug日誌:

1.把K[]開成了bool數組,還覺得本身讀入讀炸了

2.思路bug,傻不愣登的覺得將K[i]點和某個連通塊合併之後,若是又有一個屬於這個連通塊的點與K[i]有邊,會影響答案。而後考慮丟點的時候,直接用head[K[i]]!=0判斷是否是又自成一連通塊了,忘記它有的點還沒加進來。

3.順手什麼的太噁心了。習慣於

for(int i=head[u],v;i;i=e[i].nxt)
    v=e[i].to;

的寫法,因而就寫成了:

for(int j=head[u],v;j;;j=e[i].nxt)
    v=e[i].to;
相關文章
相關標籤/搜索