一定注意,这里不要写错:
$low[y]>=dfn[x]$,开始的时候把 $dfn[x]$ 写成 $low[x]$ 调了一下午......
然后根据圆方树优美的性质,我们发现题中要求的就是圆方树上一些点构成的树链的并中圆点个数.
这个问题可以用虚树或树链的并解决.
code:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define N 200006 #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout) using namespace std; vector<int>G[N]; int edges,tim,fr,tot,n,m,Q; int hd[N<<1],to[N<<1],nex[N<<1],dfn[N],low[N],S[N]; int dn[N],dep[N],size[N],son[N],top[N],fa[N],depth[N]; int arr[N]; bool cmp(int a,int b) { return dn[a]<dn[b]; } void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } void tarjan(int x) { dfn[x]=low[x]=++tim; S[++fr]=x; for(int i=hd[x];i;i=nex[i]) { int y=to[i]; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) { ++tot; G[x].push_back(tot); G[tot].push_back(x); for(int p=0;p!=y;--fr) { p=S[fr]; G[tot].push_back(p); G[p].push_back(tot); } } } else { low[x]=min(low[x],dfn[y]); } } } void dfs1(int x,int ff) { dn[x]=++tim,depth[x]=depth[ff]+1; fa[x]=ff,size[x]=1,dep[x]=dep[ff]+(x<=n); for(int i=0;i<G[x].size();++i) { int y=G[x][i]; if(y==ff) continue; dfs1(y,x); if(size[y]>size[son[x]]) son[x]=y; size[x]+=size[y]; } } void dfs2(int x,int tp) { top[x]=tp; if(son[x]) dfs2(son[x],tp); for(int i=0;i<G[x].size();++i) { if(G[x][i]!=fa[x]&&G[x][i]!=son[x]) dfs2(G[x][i],G[x][i]); } } int get_lca(int x,int y) { while(top[x]!=top[y]) { depth[top[x]]>depth[top[y]]?x=fa[top[x]]:y=fa[top[y]]; } return depth[x]<depth[y]?x:y; } void calc() { int num,lca; scanf("%d",&num); for(int i=1;i<=num;++i) scanf("%d",&arr[i]); sort(arr+1,arr+1+num,cmp); for(int i=1;i<=num;++i) { if(i==1) lca=arr[1]; else lca=get_lca(lca,arr[i]); } int ans=0; for(int i=1;i<=num;++i) ans+=dep[arr[i]]-dep[fa[lca]]; for(int i=2;i<=num;++i) { int p=get_lca(arr[i],arr[i-1]); ans-=(dep[p]-dep[fa[lca]]); } printf("%d\n",ans-num); } void solve() { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) { int x,y; scanf("%d%d",&x,&y); add(x,y),add(y,x); } tot=n; tarjan(1); tim=0; dfs1(1,0); dfs2(1,1); scanf("%d",&Q); for(int i=1;i<=Q;++i) calc(); for(int i=0;i<=2*n;++i) { G[i].clear(); low[i]=dfn[i]=son[i]=dep[i]=depth[i]=fa[i]=0; } for(int i=0;i<=edges;++i) nex[i]=to[i]=0; for(int i=0;i<=n;++i) hd[i]=0; edges=tim=fr=tot=0; } int main() { // setIO("input"); int T; scanf("%d",&T); while(T--) solve(); return 0; }