[BZOJ5329][SDOI2018]战略游戏(圆方树+虚树)
题意:一张无向图,每次给出一个点集,问有多少个点满足删去它后,存在点集中的两个点不连通。
算法:显然的圆方树+虚树。
建出圆方树后,答案就是所有关键点之间的路径上的圆点个数,这个直接用虚树,维护树上前缀和与右链即可。
虚树一万年不会建。。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define rep(i,l,r) for (int i=(l),_=(r); i<=_; i++) 5 #define mem(a) memset(a,0,sizeof(a)) 6 using namespace std; 7 8 const int N=400010; 9 int n,tot,k,u,v,m,T,Q,top,clk,L[N],R[N],dfn[N],low[N],tim,stk[N]; 10 int fa[N],Top[N],dep[N],dis[N],s[N],sz[N],son[N],q[N]; 11 struct E{ 12 int cnt,h[N],nxt[N],to[N]; 13 void init(){ mem(h); cnt=0; } 14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 15 }G,G1; 16 17 void Tarjan(int x,int fa){ 18 dfn[x]=low[x]=++tim; stk[++top]=x; 19 for (int i=G.h[x],k; i; i=G.nxt[i]) 20 if ((k=G.to[i])!=fa){ 21 if (!dfn[k]){ 22 Tarjan(k,x); low[x]=min(low[x],low[k]); 23 if (low[k]>=dfn[x]){ 24 tot++; int t; G1.add(x,tot); 25 do { t=stk[top--]; G1.add(tot,t); } while (t!=k); 26 } 27 }else low[x]=min(low[x],dfn[k]); 28 } 29 } 30 31 void dfs1(int x){ 32 dep[x]=dep[fa[x]]+1; dis[x]=dis[fa[x]]+(x<=n); sz[x]=1; 33 for (int i=G1.h[x]; i; i=G1.nxt[i]){ 34 int k=G1.to[i]; fa[k]=x; dfs1(k); sz[x]+=sz[k]; 35 if (sz[k]>sz[son[x]]) son[x]=k; 36 } 37 } 38 39 void dfs2(int x,int tp){ 40 Top[x]=tp; L[x]=++clk; 41 if (son[x]) dfs2(son[x],tp); 42 for (int i=G1.h[x],k; i; i=G1.nxt[i]) 43 if ((k=G1.to[i])!=son[x]) dfs2(k,k); 44 R[x]=clk; 45 } 46 47 int LCA(int u,int v){ 48 for (; Top[u]!=Top[v]; u=fa[Top[u]]) 49 if (dep[Top[u]]<dep[Top[v]]) swap(u,v); 50 return dep[u]<dep[v] ? u : v; 51 } 52 53 bool cmp(int a,int b){ return L[a]<L[b]; } 54 55 int main(){ 56 freopen("bzoj5329.in","r",stdin); 57 freopen("bzoj5329.out","w",stdout); 58 for (scanf("%d",&T); T--; ){ 59 scanf("%d%d",&n,&m); tot=n; 60 tim=clk=0; mem(dfn); mem(son); G.init(); G1.init(); 61 rep(i,1,m) scanf("%d%d",&u,&v),G.add(u,v),G.add(v,u); 62 rep(i,1,n) if (!dfn[i]) Tarjan(i,0); 63 dfs1(1); dfs2(1,1); 64 for (scanf("%d",&Q); Q--; ){ 65 scanf("%d",&k); int len=k; 66 rep(i,1,k) scanf("%d",&s[i]); 67 sort(s+1,s+k+1,cmp); 68 rep(i,1,k-1) s[++len]=LCA(s[i],s[i+1]); 69 sort(s+1,s+len+1,cmp); len=unique(s+1,s+len+1)-s-1; 70 int tp=0,ans=(s[1]<=n); 71 rep(i,1,len){ 72 while (tp && R[q[tp]]<L[s[i]]) tp--; 73 if (tp) ans+=dis[s[i]]-dis[q[tp]]; 74 q[++tp]=s[i]; 75 } 76 printf("%d\n",ans-k); 77 } 78 } 79 return 0; 80 }