NKOJ 2107 【并查集】可爱的猴子

NKOJ 2107 【并查集】可爱的猴子

思路:普通并查集+图的遍历更新答案

实现方法

  • 首先使用时光倒流思想解决删边的问题。
  • 注意提前把没有删过的边提前建上。
  • 接着用一个图记录猴子之间的拉手关系,每次要更新答案时都遍历与当前节点连着的节点将其答案更新,只有在 \(1\) 号节点与当前节点断开时才更新答案。

代码

#include<cstdio>
using namespace std;
int n,m,cnt;
int mks[400005][5],ltg[400005][5],last[400005];
int del[400005][5],ans[400005],vis[400005];
struct node{int pre,to;}adj[400005];
void Add(int x,int y){adj[++cnt].to=y,adj[cnt].pre=last[x],last[x]=cnt;}
int f[400005];
int getf(int x){
	if(x==f[x]) return f[x];
	return f[x]=getf(f[x]);
}
void dfs(int x,int now){
	ans[x]=now;
	vis[x]=1;
	for(int i=last[x];i;i=adj[i].pre){
		int lzh=adj[i].to;
		if(vis[lzh]==0){
			dfs(lzh,now);
		}
	}
	vis[x]=0;
}
void merge(int x,int y,int now){
	int fx=getf(x),fy=getf(y);
	if(fx==fy) return;
	if(now==-1){
		f[fx]=fy;
		return;
	}
	if(fx==getf(1)) dfs(fy,now);
	else if(fy==getf(1)) dfs(fx,now);
	f[fx]=fy,Add(x,y),Add(y,x);
}
/*错误示范
void merge(int x,int y,int now){
	int fx=getf(x),fy=getf(y);
	if(fx==fy) return;
	if(fx==getf(1)&&now!=-1) dfs(fy,now);
	else if(fy==getf(1)&&now!=-1) dfs(fx,now);
	f[fx]=fy,Add(x,y),Add(y,x);//加第二次
}
*/
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=n;i++) scanf("%d%d",&mks[i][1],&mks[i][2]);
	for(int i=1;i<=m;i++) scanf("%d%d",&ltg[i][1],&ltg[i][2]),del[ltg[i][1]][ltg[i][2]]=1;
	for(int i=1;i<=n;i++){
		if(mks[i][1]!=-1&&!del[i][1]) merge(i,mks[i][1],-1),Add(i,mks[i][1]),Add(mks[i][1],i);//加一次
		if(mks[i][2]!=-1&&!del[i][2]) merge(i,mks[i][2],-1),Add(i,mks[i][2]),Add(mks[i][2],i);
	}
	for(int i=m;i>=1;i--){
		int x=ltg[i][1],y=mks[ltg[i][1]][ltg[i][2]];
		merge(x,y,i);
	}
	for(int i=1;i<=n;i++){
		printf("%d\n",ans[i]-1);
	}

	return 0;
}

注意事项

  1. 一定注意在 merge 的时候注意不要重复加边,会T。
posted @ 2024-12-14 10:00  hsr_ray  阅读(18)  评论(0)    收藏  举报