ZOJ_3261_逆并查集

ZOJ 3261 逆并查集

  • 思路简单代码繁琐一直wa调了一天,真的菜
  • 因为并查集没有摧毁边的操作,那我们不妨先合并所有边中 不会被摧毁的边,那么就需要我们先保存所有的边,(这里太繁琐容易出错)
  • 开一个数组记录每个点的,因为要找值最大 或者 值相同但点最小的点,在合并的时候根据这个来合并,值小的指向值大的,(值相同时,大点指向小点)
  • 这里用了一个技巧就是 map<pair<int,int> , int> 除去被摧毁的边,然后从遍历map合并边.
坑点
  1. 注意存边的数组大小,
  2. 初始化和清除map,
  3. 每组数据输出一个空行
  4. merge(a,b)时保证a<b,这样merge()规定的顺序才有意义
#include <iostream>
#include <string.h>
#include <map>
#include <string>

using namespace std;

const int maxn = 1e4+5;
int pre[maxn];
int rala[maxn];
int ans[5*maxn];
struct A {
	int a,b;
} e[2*maxn];
struct node {
	bool f;
	int a,b;
} q[5*maxn];
map<pair<int,int>,int> vis;
void init() {
	for (int i=0; i<maxn; i++) pre[i] = i;
	vis.clear();
}

int find(int x) {
	if (x == pre[x]) return x;
	return  pre[x] = find(pre[x]);
}
void merge(int a,int b) {
	int ra = find(a);
	int rb = find(b);
	if (ra == rb) return ;
	if (rala[ra] > rala[rb]) pre[rb] = ra;
	else if (rala[ra] < rala[rb]) pre[ra] = rb;
	else if (rala[ra] == rala[rb]) {
		if (ra > rb) pre[ra] = rb;
		else pre[rb] = ra;
	}
	return ;
}
int n,Q,cnt;
int main() {
//	freopen("a.txt","r",stdin);
	bool mk=0;
	while (scanf("%d",&n) != EOF) {
		init();
		for (int i=0; i<n; i++) cin >> rala[i];
		int k;
		cin >> k;
		for (int i=0; i<k; i++) {
			int a,b;
			cin >> a >> b;
			if (a > b) swap(a,b);
			e[i].a = a;
			e[i].b = b;
			vis[{a,b}] = 1;
		}
		cin >> Q;
		for (int i=0; i<Q; i++) {
			string s;
			cin >> s;
			if (s == "query") {
				int x;
				cin >> x;
				q[i].a = x;
				q[i].f = 0;
			}
			else {
				int a,b;
				cin >> a >> b;
				if (a>b) swap(a,b);
				q[i].a = a;
				q[i].b = b;
				q[i].f = 1;
				vis[{a,b}] = 0;
			}
		}
		map<pair<int,int>,int>::iterator it;
		for (it=vis.begin(); it!=vis.end(); it++) 
			if (it->second) 
				merge(it->first.first,it->first.second);
		
		cnt = Q;
		for (int i=Q-1; i>=0; i--) {
			if (q[i].f == 0) { //查询
				cnt--;
				int cur = q[i].a;
				if (rala[find(cur)] > rala[cur] ) ans[cnt] = find(cur);
				else ans[cnt] = -1;
			}
			else merge(q[i].a,q[i].b);
		}
		if (mk) printf("\n");		
		else mk = 1;
		for (int i=cnt; i<Q; i++) 
			printf("%d\n",ans[i]);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值