BZOJ 4195 - 离散化 + 并查集

NOI 2015 Day1 T1啊… 学(nao'bu)了一下离散化,跟哈希的写法差不多咯… 大概的想法就是搞一个struct,两个域,分别储存原值和排序后的编号(也就是离散化之后的值)。然后利用这个二分查找一下即可。举个例子,原序列排序后为$ 1, 2, 5, 1000, 25000 $,然后我们分别重新赋予编号\(1, 2, 3, 4, 5\)。当我们要查找其中一个元素时,如\(1000\),我们就在原值的域中二分一下,即可查找到它对应的离散化后的编号\(4\)。这样,我们的空间复杂度就由\(O(max\{a_i\})\)变成了\(O(n)\)。剩下的就是基础的并查集了:由于本题是离线的,所以先把所有的等于的约束处理一遍,然后判断每一个不等于号是否满足即可。代码如下:

// BZOJ 4195

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

 #define rep(i,a,b) for (int i=a; i<=b; i++)
 #define read(x) scanf("%d", &x)
 
 const int N = 1000000+5;

 int T, n, a[N], b[N], e[N], fa[N*2], map[N*2];
 // 本题map的代码实现是不需要开两个域的,——排序后的下标就是离散后的值

 int search(int x) {
 	int l = 0, r = 2*n+1;
 	while (l+1 < r) {
 		int mid = (l+r)>>1;
 		if (map[mid] <= x) l = mid; else r = mid;
 	}
 	while (map[l-1]==map[l]) l--;
 	return l;
 }

 int find(int x) { return fa[x]==x ? x : fa[x] = find(fa[x]); }

int main()
{
	read(T);
	while (T--) {
		read(n);
		rep(i,1,2*n) fa[i] = i;
		map[0] = -1;
		rep(i,1,n) {
			read(a[i]); read(b[i]); read(e[i]);
			map[2*i-1] = a[i];
			map[2*i] = b[i];
		}
		sort(map+1, map+n*2+1);
		rep(i,1,n) {
			if (e[i]==0) continue;
			int x = search(a[i]), y = search(b[i]);
			int fx = find(x), fy = find(y);
			if (fx!=fy) fa[fx] = fy;
		}
		bool ans = true;
		rep(i,1,n) {
			if (e[i]==1) continue;
			int x = search(a[i]), y = search(b[i]);
			int fx = find(x), fy = find(y);
			if (fx==fy) { ans = false; break; }
		}
		printf(ans ? "YES" : "NO"); 
		puts("");
	}

	return 0;
}

posted @ 2016-01-18 19:25  Armeria  阅读(661)  评论(0编辑  收藏  举报