ZOJ 3984 Graph Generator(2017CCPC秦皇島 D)可撤銷並查集+思維

題目傳送門

題意:

T組數據,每組數據給你n(<=1e5)個點,m(<=min(1e5,n*(n-1)/2))條無向邊,你需要構造一個合法的序列,其中每一項輸出三個數:

點x,你選擇的點集的大小,然後給出這些點。(初始爲空圖,之後系統會增加一個新點x,並將x與你給出的這些點所在的連通塊的每一個結點連邊!)

最後形成題中給你的圖。問你是否存在合法方案,如果存在輸出Yes和任意一種方案,否則輸出No。

思路:

直接正着做找合法序列太難了,我們考慮從原圖往下一個一個拆點,拆成一個合法序列,最後倒着輸出。

注意到我們拆這一個點u,它的度數 必須 等於 所在連通塊的大小 -1 。

因此我們將所有點按度數從小到大排序,先用並查集(注意,這裏用的是可撤銷並查集,因爲要拆點會造成連通塊數變多,不能路徑壓縮!!!)建立初始的連通塊,記錄度數大的點向度數小的點連的邊。

之後再從度數最大的點開始拆,一直拆到度數最小的點(顯然度數最大的點一定是後面才添加進圖裏去的)。

對於某個點u,如果它的度數d[u] != u所在的連通塊的大小 -1 則答案一定不存在。否則u點便可以拆下來。

然後更新u所連的所有點的度數(顯然連的點的度數一定小於等於u的度數)。然後撤銷u向度數小的點連的邊,記錄答案。

並查集這一塊還是用的不夠熟練,還需要多加練習。

代碼:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define mst(head,x,n) memset(head+1,x,n*sizeof(head[0]))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int maxn=1e5+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
int n,m,k;
int mp[maxn];
int tmp,cnt;
int flag;
bool ok[maxn];
vector<int>vc[maxn];
template <typename T>
inline void read(T &X){
    X=0;int w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    if(w) X=-X;
}
struct node{
    int x,y,fax,szx,hx;
}stk[maxn];
struct st{
    int id;
    int v;
}d[maxn];
struct BCJ{
    int fa[maxn];
    int sz[maxn];
    int h[maxn];
    void init(int n){
        cnt=0;
        rep(i,0,n){
            fa[i]=-1;
            sz[i]=1;
            h[i]=0;
        }
    }
    int find(int x){return fa[x]==-1?x:find(fa[x]);}
    int un(int ox,int oy){
        int x=find(ox);
        int y=find(oy);
        if(x==y) return 0;
        if(h[x]>h[y]) swap(x,y);
        if(h[x]==h[y]) h[y]++;
        stk[++cnt]=node{x,y,fa[x],sz[x],h[x]};
        fa[x]=y;
        sz[y]+=sz[x];
        return 1;
    }
    void undo(int num){
        while(num--){
            node k=stk[cnt--];
            h[k.x]=k.hx;
            sz[k.y]-=k.szx;
            fa[k.x]=k.fax;
        }
    }
    int get(int x){
        x=find(x);
        return sz[x];
    }
}bcj;
bool cmp(st x,st y){
    return x.v<y.v||(x.v==y.v&&x.id<y.id);
}
int main(){

#ifdef ONLINE_JUDGE
#else
    freopen("D:/Temp/in.txt", "r", stdin);
#endif

    int T,cas=1;
    read(T);
    while(T--)
    {
        //cout<<" &^% "<<endl;
        read(n);read(m);
        bcj.init(n);
        rep(i,1,n) {
            vc[i].clear();
            d[i].v=0;
            d[i].id=i;
            ok[i]=false;
        }
        rep(i,1,m){
            int u,v;
            read(u);read(v);
            vc[u].push_back(v);
            vc[v].push_back(u);
            d[u].v++;d[v].v++;
        }
        sort(d+1,d+1+n,cmp);
        vector<vector<int> >tp(n+1);
        //cout<<" *&(^^ "<<endl;
        for(int i=1;i<=n;i++){
            int u=d[i].id;
            mp[u]=i;
            for(int j=0;j<vc[u].size();j++){
                int v=vc[u][j];
                if(!ok[v]) continue;
                if(bcj.un(u,v)){
                    tp[u].push_back(v);
                }
            }
            ok[u]=true;
        }
        //cout<<" *&(^^ "<<endl;
        vector<pair<int,vector<int> > >ans;
        int fg=1;
        dep(i,n,1){
            int u=d[i].id;
            //cout<<u<<" "<<d[i].v<<" "<<bcj.get(u)-1<<endl;
            if(d[i].v!=bcj.get(u)-1) {
                puts("No");
                fg=0;
                break;
            }
            for(int j=0;j<vc[u].size();j++){
                int v=vc[u][j];
                d[mp[v]].v--;
            }
            ans.push_back(make_pair(u,tp[u]));
            bcj.undo(tp[u].size());
        }
        if(!fg) continue;
        puts("Yes");
        reverse(ans.begin(),ans.end());
        for(int i=0;i<ans.size();i++){
            int nm=ans[i].first;
            vector<int> mm=ans[i].second;
            int msz=mm.size();
            printf("%d %d",nm,msz);
            for(int j=0;j<msz;j++){
                printf(" %d",mm[j]);
            }
            puts("");
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章