题意
给出一个n个点m条边的无向图,每次询问给出一个点集V,问有多少个点满足不属于V且在去掉该点后点集V中的点不连通。
n≤105,m≤2∗105
n
≤
10
5
,
m
≤
2
∗
10
5
分析
先把原图的圆方树搞出来,不难发现答案就是给出的点集所构成的虚树上有多少个圆点。
直接搞就好了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
const int N=100005;
int n,m,cnt,last[N],dfn[N],low[N],sz,tot,a[N],top,stack[N*2],tim;
struct edge{int to,next;}e[N*4];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}
bool cmp(int x,int y);
struct Data
{
int cnt,last[N*2],fa[N*2],dep[N*2],size[N*2],df[N*2],w[N*2],top[N*2];
struct edge{int to,next;}e[N*4];
void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}
void dfs1(int x)
{
dep[x]=dep[fa[x]]+1;w[x]=w[fa[x]]+(x<=n);
df[x]=++tim;size[x]=1;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa[x]) continue;
fa[e[i].to]=x;
dfs1(e[i].to);
size[x]+=size[e[i].to];
}
}
void dfs2(int x,int chain)
{
top[x]=chain;int k=0;
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=fa[x]&&size[e[i].to]>size[k]) k=e[i].to;
if (k) dfs2(k,chain);
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=k&&e[i].to!=fa[x]) dfs2(e[i].to,e[i].to);
}
int get_lca(int x,int y)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) std::swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
void solve()
{
int ans=1,top=0;bool flag=0;
stack[++top]=1;
std::sort(a+1,a+tot+1,cmp);
if (a[1]==1) flag=1;
for (int i=1;i<=tot;i++)
{
if (stack[top]==a[i]) continue;
int lca=get_lca(a[i],stack[top]);
if (lca==stack[top]) {stack[++top]=a[i];continue;}
while (top>1&&dep[stack[top-1]]>=dep[lca]) ans+=w[stack[top]]-w[stack[top-1]],top--,flag|=(stack[top]==1);
if (dep[stack[top]]>dep[lca]) ans+=w[stack[top]]-w[lca],flag|=(lca==1),top--;
if (stack[top]!=lca) stack[++top]=lca;
stack[++top]=a[i];
}
while (top>1) ans+=w[stack[top]]-w[stack[top-1]],top--;
if (!flag) ans-=w[fa[stack[2]]];
printf("%d\n",ans-tot);
}
}t;
bool cmp(int x,int y)
{
return t.df[x]<t.df[y];
}
void tarjan(int x,int fro)
{
dfn[x]=low[x]=++tim;
for (int i=last[x];i;i=e[i].next)
{
if (i==(fro^1)) continue;
if (!dfn[e[i].to])
{
stack[++top]=i;
tarjan(e[i].to,i);
low[x]=std::min(low[x],low[e[i].to]);
if (low[e[i].to]>=dfn[x])
{
sz++;int y=0;t.addedge(sz+n,x);
while (y!=i)
{
y=stack[top];top--;
t.addedge(sz+n,e[y].to);
}
}
}
else low[x]=std::min(low[x],dfn[e[i].to]);
}
}
int main()
{
int T=read();
while (T--)
{
n=read();m=read();cnt=1;
memset(last,0,sizeof(last));
memset(dfn,0,sizeof(dfn));
t.cnt=tim=sz=0;
memset(t.last,0,sizeof(t.last));
memset(t.fa,0,sizeof(t.fa));
for (int i=1;i<=m;i++)
{
int x=read(),y=read();
addedge(x,y);
}
tarjan(1,0);
tim=0;
t.dfs1(1);
t.dfs2(1,1);
int q=read();
while (q--)
{
tot=read();
for (int i=1;i<=tot;i++) a[i]=read();
t.solve();
}
}
return 0;
}