战略游戏题解
战略游戏:
题目描述
省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏。
这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着道路走到任意其他城市。现在小C已经占领了其中至少两个城市,小Q可以摧毁一个小C没占领的城市,同时摧毁所有连接这个城市的道路。只要在摧毁这个城市之后能够找到某两个小C占领的城市u和v,使得从u出发沿着道路无论如何都不能走到v,那么小Q就能赢下这一局游戏。
小Q和小C一共进行了q局游戏,每一局游戏会给出小C占领的城市集合S
你需要帮小Q数出有多少个城市在他摧毁之后能够让他赢下这一局游戏。
输入
第一行包含一个正整数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
输出
对于每一局游戏,输出一行,包含一个整数,表示这一局游戏中有多少个城市在小Q摧毁之后能够让他赢下这一局游戏。
样例输入
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
样例输出
0
1
3
0
1
2
3
题意:
无向连通图,
有q个询问,每次给出一点集S
求能使S任意两点不连通的点数(S中的点除外)。
思路:
是谁在上面放了一个虚树标签,害得蒟蒻学了半天的虚树。
其实并不需要虚树。
我们先用圆方树将图转化为树,
题目就变成了求包含这些点的最小子图的点数-|S|。
“求包含这些点的最小子图”我们可以用虚树,
但这里并不需要树型DP。
所以我们将点按dfs序排序,求出相邻两点之间的距离和,
因为每条边会遍历两边,所以最后除以2就行。
当然,这个子图中深度最低的点可能是圆点,我们需要加1。
代码:
1 #include<bits/stdc++.h> 2 #define re register 3 using namespace std; 4 const int N=2e5+6,M=4e5+6; 5 int n,m,cnt,deep,top,t1,t2,q,p,ans,c; 6 int head[N],head2[N<<1],dfn[N],low[N],s[N<<1],w[N<<1],f[N<<1][22],d[N<<1],x[N<<1]; 7 struct edge 8 { 9 int nxt,to; 10 }e[M],g[M]; 11 inline void add(int u,int v){e[++cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt;} 12 inline void add2(int u,int v){g[++cnt].nxt=head2[u]; g[cnt].to=v; head2[u]=cnt;} 13 inline int read() 14 { 15 int T=0,F=1; char ch=getchar(); 16 while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();} 17 while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar(); 18 return F*T; 19 } 20 void tarjan(int u) 21 { 22 //cout<<u<<endl; 23 dfn[u]=low[u]=++deep; s[++top]=u; int t; 24 for(int i=head[u];i;i=e[i].nxt) 25 { 26 t=e[i].to; 27 if(!dfn[t]) 28 { 29 tarjan(t),low[u]=min(low[u],low[t]); 30 if(low[t]>=dfn[u]) 31 { 32 ++t1; w[t1]=0; add2(u,t1); 33 while(s[top+1]!=t) add2(t1,s[top]),--top; 34 } 35 } 36 else low[u]=min(low[u],dfn[t]); 37 } 38 } 39 void dfs(int u,int fa) 40 { 41 f[u][0]=fa; d[u]=d[fa]+1; w[u]+=w[fa]; dfn[u]=++cnt; 42 for(int i=1;i<=20;++i) f[u][i]=f[f[u][i-1]][i-1]; 43 for(int i=head2[u];i;i=g[i].nxt) dfs(g[i].to,u); 44 } 45 inline int lca(int u,int v) 46 { 47 if(d[u]<d[v]) swap(u,v); 48 for(int i=20;i>=0;--i) if(d[u]>=d[v]+(1<<i)) u=f[u][i]; 49 if(u==v) return u; 50 for(int i=20;i>=0;--i) 51 { 52 if(f[u][i]==f[v][i]) continue; 53 u=f[u][i],v=f[v][i]; 54 } 55 return f[u][0]; 56 } 57 inline int dis(int u,int v){int o=lca(u,v); return w[u]-w[o]+w[v]-w[o];} 58 bool cmp(int u,int v){return dfn[u]<dfn[v];} 59 int main() 60 { 61 c=read(); 62 while(c--) 63 { 64 n=read(),m=read(); cnt=top=0; memset(head,0,sizeof(head)); memset(head2,0,sizeof(head2)); memset(s,0,sizeof(s)); 65 memset(w,0,sizeof(w)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(f,0,sizeof(f)); 66 for(re int i=1;i<=n;++i) w[i]=1; 67 for(re int i=1;i<=m;++i) t1=read(),t2=read(),add(t1,t2),add(t2,t1); t1=n; cnt=0; 68 tarjan(1); memset(dfn,0,sizeof(dfn)); cnt=0; dfs(1,0); q=read(); 69 for(re int i=1;i<=q;++i) 70 { 71 t1=read(); top=0; ans=0; 72 for(int j=1;j<=t1;++j) x[j]=read(); 73 sort(x+1,x+t1+1,cmp); 74 for(int j=1;j<t1;++j) ans+=dis(x[j],x[j+1]); 75 ans+=dis(x[t1],x[1]); 76 printf("%d\n",ans/2-t1+(lca(x[t1],x[1])<=n)); 77 } 78 } 79 return 0; 80 }