20211229[按秩合并并查集 最小生成树][BZOJ4668]冷战

20211229[按秩合并并查集、最小生成树][BZOJ4668]冷战

题意:给定N点,动态加边与询问两点最早是哪条边开始连通,强制在线

首先如果离线的话可以直接跑最小生成树,不过代码不好处理。
当然可以选择二分+并查集判连通,不过只有60分
正解是不进行压缩路径的并查集进行合并,并且将加入时间作为边权,查询的话可以暴力跑两个点之间的最大边权即可。
但是在做的时候还是想过有没有合适的数据结构可以预维护并查集内的点集还有两点间的关系,因为这样的话查询说不定可以避免O(n),想过vector,但是50W的数据显然不能用二维数组存储连通关系,不知道有没有什么巨佬方法可以做到。

#include<cstdio>
#define maxn 500039
#define max(a, b) ((a)>(b)?(a):(b))
using namespace std;
int N, M, ans, f[maxn] ,h[maxn], cnt, w[maxn], cnt2, g[maxn], root;
int find(int x){return f[x]==x?x:find(f[x]);}
int main(){
	freopen("1.in", "r", stdin);
	scanf("%d%d", &N, &M);
	int opt, u, v, x, y;
	for(int i = 1; i < N+1; i++){
		h[i] = 1;
		f[i] = i;
	}
	while(M--){
		scanf("%d%d%d", &opt, &u, &v);
		cnt2++;
		u^=ans; v^=ans;
		if(opt){
			x = find(u), y = find(v);
			int maxx = 0;
			if(x!=y)
				printf("0\n");
			else{
				x = u, y = v;
				while(g[u]!=cnt2){ //找祖先,很蠢的做法,常熟较大
					g[u]=cnt2;
					u = f[u];
				}
				while(g[v]!=cnt2){
					v = f[v];
				}
				root = v;
				u = x, v = y;
				while(u!=root){  //跑最大值
					maxx = max(maxx, w[u]);
					u = f[u];
				}
				while(v!=root){
					maxx = max(maxx, w[v]);
					v = f[v];
				}
				printf("%d\n", maxx);
			}
			ans = maxx;
		}
		else{
			cnt++;
			x = find(u), y = find(v);
			if(x!=y){
				if(h[x]<h[y]){ //按秩合并
					f[x] = y;
					h[y] += h[x];
					w[x] = cnt;
				}
				else{
					f[y] = x;
					h[x] += h[y];
					w[y] = cnt;
				}
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值