Description
给一个无向连通图,多次询问一个点集S,问去掉哪些点后S集合不连通,S中的点显然不能算。
n
≤
2
∗
1
0
5
,
  
∑
∣
S
∣
≤
2
∗
1
0
5
n\le2*10^5,\; \sum {|S|}\le2*10^5
n≤2∗105,∑∣S∣≤2∗105
Solution
会破坏连通性的点容易发现就是建好圆方树后的圆点
我们把S集的虚树搞出来,求一下这个虚树内部有多少个圆点就是答案了。
实际操作中并不需要建出树形结构,我们按照dfs排序然后求一下相邻两点形成链上的圆点数量就行
注意特判一下虚树的根是不是圆点
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef long long LL;
const int N=2000005;
const int E=2000005;
struct edge {int x,y,next;} ;
int n;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
struct Graph {
int fa[N],dep[N],pos[N],size[N];
int ls[N],bl[N],w[N],edCnt;
edge e[E];
pair a[N];
edge operator [](int x) {
return e[x];
}
void clear() {
fill(ls,0);
fill(pos,0);
edCnt=0;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
// printf("%d %d\n", x,y);
}
void dfs1(int x) {
size[x]=1;
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa[x]) continue;
fa[e[i].y]=x; dep[e[i].y]=dep[x]+1;
w[e[i].y]=w[x]+(e[i].y<=n);
dfs1(e[i].y); size[x]+=size[e[i].y];
}
}
void dfs2(int x,int up) {
bl[x]=up; pos[x]=++pos[0];
int mx=0;
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y!=fa[x]&&size[e[i].y]>size[mx]) mx=e[i].y;
}
if (!mx) return ;
dfs2(mx,up);
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y!=fa[x]&&e[i].y!=mx) dfs2(e[i].y,e[i].y);
}
}
int get_lca(int x,int y) {
for (;bl[x]^bl[y];x=fa[bl[x]]) {
if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y);
}
return dep[x]<dep[y]?x:y;
}
void solve() {
int k=read();
rep(i,1,k) {
int x=read(),y=pos[x];
a[i]=pair(y,x);
}
std:: sort(a+1,a+k+1);
LL ans=0; int rt=a[1].se;
a[0]=a[k];
rep(ti,1,k) {
int now=a[ti].se,pre=a[ti-1].se;
int lca=get_lca(now,pre);
if (dep[lca]<dep[rt]) rt=lca;
ans+=w[now]+w[pre]-w[lca]*2;
}
// printf("%lld ", ans);
printf("%lld\n", ans/2+(rt<=n)-k);
}
} G;
int dfn[N],low[N],tot;
int ls[N],edCnt;
edge e[N];
std:: stack <int> stack;
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
}
void dfs(int x,int from) {
dfn[x]=low[x]=++dfn[0];
for (int i=ls[x];i;i=e[i].next) {
if ((i^1)==from) continue;
if (!dfn[e[i].y]) {
stack.push(i); dfs(e[i].y,i);
low[x]=std:: min(low[x],low[e[i].y]);
if (dfn[x]<=low[e[i].y]) {
int y=0; ++tot;
while (y!=i) {
y=stack.top(); stack.pop();
G.add_edge(e[y].y,tot);
}
G.add_edge(x,tot);
}
} else low[x]=std:: min(dfn[e[i].y],low[x]);
}
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
for (int Case=read(),wjp=0;Case--;) {
G.clear(); edCnt=1;
fill(ls,0),fill(dfn,0);
while (stack.size()) stack.pop();
n=read(); int m=read();
rep(i,1,m) add_edge(read(),read());
tot=n;
dfs(1,0);
G.dfs1(G.dep[1]=1);
G.dfs2(1,1);
for (int T=read();T--;) G.solve();
}
return 0;
}