GMOJ 4267. 图 题解

思路

一看到这题我就想起了gmoj3883

本质上这道题也可以用染色的思想做,先随便建一棵树,然后每条非树边都可以看成一次染色,然后新染色的数量就是答案减少的数量。

当然,如果一开始不是联通的就不行了(但其它方法也不行)。

跑一下tarjan求LCA再用并查集缩点即可。

但我没有写(一般意义上的)并查集,而是用了一种玄学的方法来做。

具体见gmoj3883题解

代码

#include<cstdio>
#include<cstring>
#define N 500010
#define now st[size] 
using namespace std;
int n,m,ans,q,s[N],last,a[N],b[N][2],ques[N][3],lca[N],up[N],dp[N],st[N],si[N];
int qlast,qa[N],qb[N][3],least[N][2];
bool nbi[N];
template<typename T>void read(T &x){
	char c=getchar();
	for(;c<33;c=getchar());
	for(x=0;(47<c)&&(c<58);x=x*10+c-48,c=getchar());
}
void add(int x,int y){
	b[++last][0]=a[x];
	b[last][1]=y;
	a[x]=last;
}
void qadd(int x,int y,int z){
	qb[++qlast][0]=qa[x];
	qb[qlast][1]=y;
	qb[qlast][2]=z;
	qa[x]=qlast;
}
int root(int m){
	return(s[m]?s[m]=root(s[m]):m);
}
void tarjan(){
	int size=1;
	st[1]=1;
	while(size){
		if(si[now]){
			s[root(b[si[now]][1])]=root(now);
			si[now]=b[si[now]][0];
		}else{
			si[now]=a[now];
		}
		for(;b[si[now]][1]==up[now]&&si[now];si[now]=b[si[now]][0]);
		if(si[now]){
			dp[b[si[now]][1]]=dp[now]+1;
			st[size+1]=b[si[now]][1];
			up[b[si[now]][1]]=now;
			size++;
		}else{
			for(int i=qa[now];i;i=qb[i][0]){
				int get=root(qb[i][1]);
				if((get!=qb[i][1])||(get==now)){
					lca[qb[i][2]]=get;
				}
			}
			size--;		
		}
	}
}
int sg(int x,int l){
	int re=0;
	for(int temp;dp[x]>dp[l];x=temp){
		temp=up[x];
		up[x]=l;             //这条语句很有趣,因为这不是并查集,如果放在下面的if内会被卡掉
		if(!nbi[x]){
			nbi[x]=1;
			re++;
		}
	}
	return(re);
}
int main(){
	read(n);read(m);
	ans=n-1;
	for(int i=1;i<=m;i++){
		int x,y;
		read(x);read(y);
		if(root(x)!=root(y)){
			add(x,y);
			add(y,x);
			s[root(x)]=root(y);
		}else{
			least[++least[0][0]][0]=x;
			least[least[0][0]][1]=y;
		}
	}
	memset(s,0,sizeof(s));
	for(int i=1;i<=least[0][0];i++){
		qadd(least[i][0],least[i][1],i);
		qadd(least[i][1],least[i][0],i);
	}
	read(q);
	for(int i=least[0][0]+1;i<=q+least[0][0];i++){
		read(ques[i][0]);read(ques[i][1]);
		qadd(ques[i][0],ques[i][1],i);
		qadd(ques[i][1],ques[i][0],i);
	}
	tarjan();
	for(int i=1;i<=least[0][0];i++){
		ans-=sg(least[i][0],lca[i])+sg(least[i][1],lca[i]);
	}
	for(int i=least[0][0]+1;i<=q+least[0][0];i++){
		ans-=sg(ques[i][0],lca[i])+sg(ques[i][1],lca[i]);
		printf("%d\n",ans);
	}
}
posted @ 2020-07-24 16:02  ToUNVRSe  阅读(95)  评论(0)    收藏  举报