【BZOJ5329】【SDOI2018】战略游戏(圆方树,虚树)

【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;
}

猜你喜欢

转载自www.cnblogs.com/cjyyb/p/9103234.html