loj#2562 「SDOI2018」战略游戏 圆方树+虚树

版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/89328926

Description


给一个无向连通图,多次询问一个点集S,问去掉哪些点后S集合不连通,S中的点显然不能算。
n 2 1 0 5 ,    S 2 1 0 5 n\le2*10^5,\; \sum {|S|}\le2*10^5

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;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/89328926