BZOJ5329: [SDOI2018]战略游戏——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5329
https://www.luogu.org/problemnew/show/P4606
省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏。这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着道路走到任意其他城市。现在小C已经占领了其中至少两个城市,小Q可以摧毁一个小C没占领的城市,同时摧毁所有连接这个城市的道路。只要在摧毁这个城市之后能够找到某两个小C占领的城市u和v,使得从u出发沿着道路无论如何都不能走到v,那么小Q就能赢下这一局游戏。小Q和小C一共进行了q局游戏,每一局游戏会给出小C占领的城市集合S,你需要帮小Q数出有多少个城市在他摧毁之后能够让他赢下这一局游戏。
圆方树很好的板子题,以及最开始我题看错了以为是最少多少步才能赢emm…
看到炸点想到tarjan点双缩点,然后套上圆方树。
然后对于询问的点集发现很小,于是套上虚树。
然后任意两个关键点之间的赢法取决于这两个关键点之间有多少圆点,话句话讲,答案就是虚树所有路径在原树上的圆点个数和。
码码码就AC了。
PS:注意虚树的根到原树的根这段路程的圆点不要统计!WA在这里。
(以及强烈吐槽对于tarjan压栈压的是点的同学你们这样做是不对的!)
#include<cmath> #include<queue> #include<stack> #include<cstdio> #include<cctype> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef double dl; const int N=2e5+5; const int B=18; const int M=N*2; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int u[M],v[M],nxt[M]; int cnt,head[N]; void init(){ cnt=0; memset(head,0,sizeof(head)); } void add(int U,int V){ u[++cnt]=U;v[cnt]=V;nxt[cnt]=head[U];head[U]=cnt; } }e,g; int n,m; int dfn[N],low[N],to[N],t,l; stack<int>q; void tarjan(int u,int f){ dfn[u]=low[u]=++t; for(int i=g.head[u];i;i=g.nxt[i]){ int v=g.v[i]; if(!dfn[v]){ q.push(i); tarjan(v,u); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]){ int num;l++; do{ num=q.top();q.pop(); int uu=g.u[num],vv=g.v[num]; if(to[uu]!=l){ to[uu]=l; e.add(uu,l+n);e.add(l+n,uu); } if(to[vv]!=l){ to[vv]=l; e.add(vv,l+n);e.add(l+n,vv); } }while(num!=i); } }else if(low[u]>dfn[v]&&f!=v){ q.push(i); low[u]=dfn[v]; } } } int anc[N][B+4],dep[N],pos[N],len[N],tot; void dfs(int u,int f){ pos[u]=++tot; dep[u]=dep[f]+1; len[u]=len[f]+(u<=n); anc[u][0]=f; for(int i=1;i<=B;i++) anc[u][i]=anc[anc[u][i-1]][i-1]; for(int i=e.head[u];i;i=e.nxt[i]){ int v=e.v[i]; if(v!=anc[u][0])dfs(v,u); } } inline int LCA(int i,int j){ if(dep[i]<dep[j])swap(i,j); for(int k=B;k>=0;--k) if(dep[anc[i][k]]>=dep[j])i=anc[i][k]; if(i==j)return i; for(int k=B;k>=0;--k) if(anc[i][k]!=anc[j][k]) i=anc[i][k],j=anc[j][k]; return anc[i][0]; } int aux[N],stk[N],fa_aux[N],top,num; bool cmp(int a,int b){return pos[a]<pos[b];} int build(int t){ sort(aux+1,aux+t+1,cmp); num=t;stk[top=0]=0; for(int i=1;i<=t;i++){ int u=aux[i]; if(!top)fa_aux[u]=0,stk[++top]=u; else{ int lca=LCA(u,stk[top]); while(dep[stk[top]]>dep[lca]){ if(dep[stk[top-1]]<=dep[lca]) fa_aux[stk[top]]=lca; top--; } if(stk[top]!=lca){ fa_aux[lca]=stk[top]; stk[++top]=lca; aux[++num]=lca; } fa_aux[u]=lca; stk[++top]=u; } } sort(aux+1,aux+num+1,cmp); } int solve(){ int ans=0; for(int i=num;i>1;i--){ int u=aux[i],v=fa_aux[u]; ans+=len[u]-len[v]; } ans+=aux[1]<=n; return ans; } inline void init(){ t=l=tot=0; e.init();g.init(); memset(to,0,sizeof(to)); memset(dfn,0,sizeof(dfn)); } int main(){ int T=read(); while(T--){ init(); n=read(),m=read(); for(int i=1;i<=m;i++){ int u=read(),v=read(); g.add(u,v);g.add(v,u); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i,0); dfs(1,0); int q=read(); while(q--){ int t=read(); for(int i=1;i<=t;i++)aux[i]=read(); build(t); printf("%d\n",solve()-t); } } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++