您好,欢迎来到图艺博知识网。
搜索
您的当前位置:首页POJ 1733 Parity Game

POJ 1733 Parity Game

来源:图艺博知识网

前缀知识


思路

离散化:

由于 n n n 太大,但查询最多只有 5 e 3 5e3 5e3 次,所以最多只有 1 e 4 1e4 1e4 个不同的数,先将查询的区间两端编号离散化。
读入时将区间 [ x , y ] [x, y] [x,y] 变为区间 ( x − 1 , y ] (x - 1, y] (x1,y](这两个是等价的),离散化时加入离散数组 h u s h hush hush 的两个数是 x − 1 x - 1 x1 y y y 而不是 x x x y y y(至于为什么这么做等会会说)。

并查集:

并查集是此题核心思路,用到的是带权并查集

我们将每个位置视为并查集生成树中的一个节点,最开始每个节点之间互无连线且都以自己为根节点

现在读入处理好的第一个操作,说某个区间 ( x , y ] (x, y] (x,y] 1 1 1 数量的奇偶性(由于离散化时左端点左移了一位,因此是左开右闭区间),我们就将节点 x x x y y y 连在一起(即 f a [ y ] = x fa[y] = x fa[y]=x)。现在 x x x 就是 y y y 所在并查集生成树的根节点(由于这是第一个操作,所以该生成树中就 x x x y y y 两个节点)。
此时我们用一个数组 d [ u ] d[u] d[u] 记录节点 u u u 到其所在并查集生成树的根节点距离(距离的定义就是:该节点到根节点所代表区间 “ 1 " “1" “1" 个数的奇偶性,取值范围就是 d [ u ] ∈ { 0 , 1 } d[u] \in {0,1} d[u]0,1 1 1 1 表示奇数, 0 0 0 表示偶数),那么 d [ y ] = 1 d[y] = 1 d[y]=1

在接下来每次操作中,每读入一组 x , y x,y x,y(代表查询的区间是 ( x , y ] (x, y] (x,y]),就看看他们是否在同一个并查集中。
若是,那么我们就可以先分别知道【 x x x 到根节点的距离】与【 y y y 到根节点的距离】,也就是它们所代表区间 1 1 1 的奇偶个数,再由 " 奇数 + + + 奇数 = = = 偶数,奇数 + + + 偶数 = = = 奇数 " 判断出区间 ( x , y ] (x, y] (x,y] 1 1 1 的奇偶个数,看看是否符合数据所给,不符就直接输出;
若不是,就将 x x x 所在并查集与 y y y 所在并查集合并。

合并细节:

f x fx fx x x x 所在并查集的根节点, f y fy fy y y y 所在并查集的根节点。
先如普通并查集一般,让 f a [ f y ] = f x fa[fy] = fx fa[fy]=fx
再更新 f y fy fy 到根节点的距离,让 d [ f y ] = d [ x ] ⊕ d [ y ] ⊕ o p d[fy] = d[x] \oplus d[y] \oplus op d[fy]=d[x]d[y]op ⊕ \oplus 是异或, o p op op 是数据给的 ( x , y ] (x, y] (x,y] “ 1 ” “1” “1” 个数的奇偶性)。

为什么是这样呢?
我们将两个区间合并,实际上是推出 f y fy fy f x fx fx 距离。

如下图, w w w 就是我们要求的 d [ f y ] d[fy] d[fy]
(图片上传不上去,以后再补)
很显然 w ⊕ d [ y ] = d [ x ] ⊕ o p w \oplus d[y] = d[x] \oplus op wd[y]=d[x]op,再给两边同时异或 d [ y ] d[y] d[y],就变成了上述式子。


代码

#include <bits/stdc++.h>

#define mkpr make_pair

using namespace std;


typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

const int maxn = 5e3 + 7;
const int inf  = 0x3f3f3f3f;

int n, m; 
struct Query {
	int x, y, op;
} q[maxn];

int hcnt, hush[maxn << 1];
unordered_map<int, int> ump;

int fa[maxn], d[maxn];
int find(int x) {
	if (x != fa[x]) {
		int rtx = find(fa[x]);
		d[x] ^= d[fa[x]];
		fa[x] = rtx;
	}
	return fa[x];
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; ++i) {
		char opt[5];
		scanf("%d%d%s", &q[i].x, &q[i].y, opt);
		q[i].op = (opt[0] == 'o' ? 1 : 0);  // 1 表示奇数, 0 表示偶数 
	    --q[i].x;
	    hush[++hcnt] = q[i].x, hush[++hcnt] = q[i].y;
	}
	
	// 离散化 
	sort(hush + 1, hush + hcnt + 1);
	hcnt = unique(hush + 1, hush + hcnt + 1) - hush - 1;
	for (int i = 1; i <= hcnt; ++i) 
	    ump[hush[i]] = i;
	for (int i = 1; i <= m; ++i)
	    q[i].x = ump[q[i].x],
	    q[i].y = ump[q[i].y];
	
	for (int i = 1; i <= hcnt; ++i) 
		fa[i] = i, d[i] = 0;
	
	for (int i = 1; i <= m; ++i) {
		int x = q[i].x, y = q[i].y;
		int fx = find(x), fy = find(y);
		
		if (fx == fy) {  // 判断是否合法
			if (d[x] == d[y] && q[i].op == 1) {
				printf("%d", i - 1);
				return 0;
			} 
			if (d[x] != d[y] && q[i].op == 0) {
				printf("%d", i - 1);
				return 0;
			}
		} else {  // 合并
		    fa[fy] = fx;
			d[fy] = d[x] ^ d[y] ^ q[i].op; 
		}
	}
	printf("%d\n", m);
	return 0;
}

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuoyibo.net 版权所有 湘ICP备2023021910号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务