1. 程式人生 > >【BZOJ5329】【SDOI2018】戰略遊戲(圓方樹,虛樹)

【BZOJ5329】【SDOI2018】戰略遊戲(圓方樹,虛樹)

FN 貢獻 地圖 return http top char Go show

【BZOJ5329】【SDOI2018】戰略遊戲(圓方樹,虛樹)

題面

BZOJ
洛谷

Description

省選臨近,放飛自我的小Q無心刷題,於是慫恿小C和他一起頹廢,玩起了一款戰略遊戲。
這款戰略遊戲的地圖由n個城市以及m條連接這些城市的雙向道路構成,並且從任意一個城市出發總能沿著道路走到
任意其他城市。現在小C已經占領了其中至少兩個城市,小Q可以摧毀一個小C沒占領的城市,同時摧毀所有連接這
個城市的道路。只要在摧毀這個城市之後能夠找到某兩個小C占領的城市u和v,使得從u出發沿著道路無論如何都不
能走到v,那麽小Q就能贏下這一局遊戲。
小Q和小C一共進行了q局遊戲,每一局遊戲會給出小C占領的城市集合S

你需要幫小Q數出有多少個城市在他摧毀之後能夠讓他贏下這一局遊戲。

Input

第一行包含一個正整數T,表示測試數據的組數,
對於每組測試數據,
第一行是兩個整數n和m,表示地圖的城市數和道路數,
接下來m行,每行包含兩個整數u和v~(1<=u<v<=n)
表示第u個城市和第v個城市之間有一條道路,同一對城市之間可能有多條道路連接,
第m+1是一個整數q,表示遊戲的局數,
接下來q行,每行先給出一個整數|S|(2<=|S|<=n)
表示小C占領的城市數量,然後給出|S|個整數s1,s2,...s|S|,(1<=s1<s2<s|S|<=n),表示小C占領的城市。

1<= T<= 10,
2<= n<= 10^5 且 n-1<= m<= 210^5,
1<= q<= 10^5,
對於每組測試數據,有Sigma|S|<= 2
10^5

Output

對於每一局遊戲,輸出一行,包含一個整數,表示這一局遊戲中有多少個城市在小Q摧毀之後能夠讓他贏下這一局遊戲。

Sample Input

2

7 6

1 2

1 3

2 4

2 5

3 6

3 7

3

2 1 2

3 2 3 4

4 4 5 6 7

6 6

1 2

1 3

2 3

1 4

2 5

3 6

4

3 1 2 3

3 1 2 6

3 1 5 6

3 4 5 6

Sample Output

0

1

3

0

1

2

3

題解

首先把一般圖構建出圓方樹,
考慮若幹個點的貢獻,
顯然是把他們連成一個最小的聯通塊,然後計算裏面的圓點個數。
這樣子答案就可以通過構建虛樹計算出答案啦。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 222222
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int Tot,n,m;
struct Line{int v,next;};
struct Link
{
    Line e[MAX<<2];
    int h[MAX],cnt;
    void init(){memset(h,0,sizeof(h));cnt=0;}
    void Add(int u,int v)
    {
        e[++cnt]=(Line){v,h[u]};h[u]=cnt;
        e[++cnt]=(Line){u,h[v]};h[v]=cnt;
    }
}G,T;
namespace Graph
{
    int dfn[MAX],low[MAX],tim,S[MAX],top;
    void init(){memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));tim=top=0;}
    void Tarjan(int u)
    {
        dfn[u]=low[u]=++tim;S[++top]=u;
        for(int i=G.h[u];i;i=G.e[i].next)
        {
            int v=G.e[i].v;
            if(!dfn[v])
            {
                Tarjan(v);low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u])
                {
                    T.Add(++Tot,u);int x;
                    do{x=S[top--];T.Add(Tot,x);}while(v!=x);
                }
            }
            else low[u]=min(low[u],dfn[v]);
        }
    }
}
namespace RST
{
    int dfn[MAX],low[MAX],tim,fa[MAX],dep[MAX],top[MAX],size[MAX],hson[MAX],dis[MAX];
    void init(){memset(hson,0,sizeof(hson));tim=0;}
    void dfs1(int u,int ff)
    {
        fa[u]=ff;size[u]=1;dep[u]=dep[ff]+1;dis[u]=dis[ff]+(u<=n);
        for(int i=T.h[u];i;i=T.e[i].next)
        {
            int v=T.e[i].v;if(v==ff)continue;
            dfs1(v,u);size[u]+=size[v];
            if(size[v]>size[hson[u]])hson[u]=v;
        }
    }
    void dfs2(int u,int tp)
    {
        top[u]=tp;dfn[u]=++tim;
        if(hson[u])dfs2(hson[u],tp);
        for(int i=T.h[u];i;i=T.e[i].next)
            if(T.e[i].v!=fa[u]&&T.e[i].v!=hson[u])
                dfs2(T.e[i].v,T.e[i].v);
        low[u]=tim;
    }
    int LCA(int u,int v)
    {
        while(top[u]^top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
        return dep[u]<dep[v]?u:v;
    }
    bool cmp(int a,int b){return dfn[a]<dfn[b];}
    int p[MAX],S[MAX],K;
    void Solve()
    {
        K=read();int ans=0,len=K;
        for(int i=1;i<=K;++i)p[i]=read();
        sort(&p[1],&p[K+1],cmp);
        for(int i=K;i>1;--i)p[++K]=LCA(p[i],p[i-1]);
        sort(&p[1],&p[K+1],cmp);K=unique(&p[1],&p[K+1])-p-1;
        ans=p[1]<=n;
        for(int i=1,tp=0;i<=K;++i)
        {
            while(tp&&low[S[tp]]<dfn[p[i]])--tp;
            if(tp)ans+=dis[p[i]]-dis[S[tp]];S[++tp]=p[i];
        }
        printf("%d\n",ans-len);
    }
}
int main()
{
    int TCase=read();
    while(TCase--)
    {
        Tot=n=read();m=read();G.init();T.init();
        for(int i=1;i<=m;++i)G.Add(read(),read());
        Graph::init();Graph::Tarjan(1);
        RST::init();RST::dfs1(1,0);RST::dfs2(1,1);
        int Q=read();
        while(Q--)RST::Solve();
    }
    return 0;
}

【BZOJ5329】【SDOI2018】戰略遊戲(圓方樹,虛樹)