1. 程式人生 > >[BZOJ5329][Sdoi2018]戰略遊戲 圓方樹+虛樹

[BZOJ5329][Sdoi2018]戰略遊戲 圓方樹+虛樹

整數 getc 如何 rip 表示 += algorithm max memset

5329: [Sdoi2018]戰略遊戲

Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 174 Solved: 109
[Submit][Status][Discuss]

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<= 2*10^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

HINT

Source

對原圖建立圓方樹,顯然答案為關鍵點間的圓點數,對圓方樹建立虛樹即可。

技術分享圖片
  1 #include<iostream>
  2
#include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 #define maxn 400005 8 using namespace std; 9 inline int read() { 10 int x=0,f=1;char ch=getchar(); 11 for(;!isdigit(ch);ch=getchar()) if(ch==-) f=-1; 12 for(;isdigit(ch);ch=getchar()) x=x*10+ch-0; 13 return x*f; 14 } 15 int T; 16 int n,m; 17 struct edge {int to,nxt;}e[maxn*2],e1[maxn*2]; 18 int head[maxn],cnt,head1[maxn],cnt1; 19 inline void add(int u,int v) {e[++cnt].nxt=head[u];e[cnt].to=v;head[u]=cnt;} 20 inline void add1(int u,int v) {e1[++cnt1].nxt=head1[u];e1[cnt1].to=v;head1[u]=cnt1;} 21 int dfn[maxn],low[maxn],tim,sta[maxn],top,tot; 22 int f[maxn][20],dep[maxn],dis[maxn]; 23 inline void init() { 24 memset(head,0,sizeof(head)); 25 memset(head1,0,sizeof(head1)); 26 memset(dfn,0,sizeof(dfn)); 27 memset(low,0,sizeof(low)); 28 memset(dis,0,sizeof(dis)); 29 memset(dep,0,sizeof(dep)); 30 memset(f,0,sizeof(f)); 31 cnt=0;cnt1=0;tim=0;top=0;tot=0; 32 } 33 inline void tarjan(int x) { 34 dfn[x]=low[x]=++tim;sta[++top]=x; 35 for(int i=head[x];i;i=e[i].nxt) { 36 int to=e[i].to; 37 if(dfn[to]) low[x]=min(low[x],dfn[to]); 38 else { 39 tarjan(to);low[x]=min(low[x],low[to]); 40 if(low[to]>=dfn[x]) { 41 ++tot; 42 while(sta[top]!=to){add1(tot,sta[top]);add1(sta[top],tot);top--;} 43 add1(sta[top],tot);add1(tot,sta[top]);top--; 44 add1(x,tot);add1(tot,x); 45 } 46 } 47 } 48 } 49 inline void dfs(int x,int fa) { 50 dfn[x]=++tim; 51 for(int i=1;i<20&&(1<<i)<=dep[x];i++) f[x][i]=f[f[x][i-1]][i-1]; 52 for(int i=head1[x];i;i=e1[i].nxt) { 53 int to=e1[i].to;if(to==fa) continue; 54 f[to][0]=x;dep[to]=dep[x]+1;dis[to]=dis[x]+(to<=n); 55 dfs(to,x); 56 } 57 } 58 inline int getlca(int x,int y) { 59 if(dep[x]<dep[y]) swap(x,y); 60 int t=dep[x]-dep[y]; 61 62 for(int i=0;i<20;i++) if((1<<i)&t) x=f[x][i]; 63 for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 64 return x==y?x:f[x][0]; 65 } 66 int a[maxn]; 67 inline bool cmp(int t1,int t2) {return dfn[t1]<dfn[t2];} 68 int main() { 69 //freopen("1.in","r",stdin); 70 //freopen("1.out","w",stdout); 71 T=read(); 72 while(T--) { 73 init(); 74 n=read(),m=read();tot=n; 75 for(int i=1;i<=m;i++) { 76 int u=read(),v=read(); 77 add(u,v);add(v,u); 78 } 79 tarjan(1);memset(dfn,0,sizeof(dfn));tim=0;dis[1]=1;dep[1]=1;dfs(1,0);top=0; 80 int Q=read(); 81 while(Q--) { 82 top=0; 83 int q=read(),ans=0; 84 for(int i=1;i<=q;i++) a[i]=read(); 85 sort(a+1,a+q+1,cmp); 86 sta[++top]=a[1]; 87 for(int i=2;i<=q;i++) { 88 int lca=getlca(a[i],sta[top]); 89 while(top>1&&dep[sta[top-1]]>=dep[lca]) { 90 ans+=dis[sta[top]]-dis[sta[top-1]];top--; 91 } 92 if(sta[top]!=lca) {ans+=dis[sta[top]]-dis[lca],sta[top]=lca;} 93 sta[++top]=a[i]; 94 } 95 while(top>1) {ans+=dis[sta[top]]-dis[sta[top-1]],top--;} 96 ans+=(sta[top]<=n)-q; 97 printf("%d\n",ans); 98 } 99 } 100 } 101
View Code

[BZOJ5329][Sdoi2018]戰略遊戲 圓方樹+虛樹