【BZOJ5329】【SDOI2018】戰略遊戲(圓方樹,虛樹)
【BZOJ5329】【SDOI2018】戰略遊戲(圓方樹,虛樹)
題面
BZOJ
洛谷
Description
省選臨近,放飛自我的小Q無心刷題,於是慫恿小C和他一起頹廢,玩起了一款戰略遊戲。
這款戰略遊戲的地圖由n個城市以及m條連接這些城市的雙向道路構成,並且從任意一個城市出發總能沿著道路走到
任意其他城市。現在小C已經占領了其中至少兩個城市,小Q可以摧毀一個小C沒占領的城市,同時摧毀所有連接這
個城市的道路。只要在摧毀這個城市之後能夠找到某兩個小C占領的城市u和v,使得從u出發沿著道路無論如何都不
能走到v,那麽小Q就能贏下這一局遊戲。
小Q和小C一共進行了q局遊戲,每一局遊戲會給出小C占領的城市集合S
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占領的城市。
2<= n<= 10^5 且 n-1<= m<= 210^5,
1<= q<= 10^5,
對於每組測試數據,有Sigma|S|<= 210^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】戰略遊戲(圓方樹,虛樹)