【POJ 1733】Parity game【带权并查集维护奇偶】

题意:

一个长度为 N N 的由 0 0 1 1 组成的序列 S S M M 个询问,返回 [ l , r ] [l,r] 1 1 的个数是奇数还是偶数。输出一个最小的 k k ,使得存在一个 01 01 序列满足第 1   k 1 1~k-1 个回答,但不存在满足第 1   k 1~k 个回答的 01 01 序列。
( N 1 0 9 , M 10000 ) (N\leq 10^9,M\leq 10000)


思路:

N N 比较大,但是询问比较少,因此需要将所有数字离散化。

然后我们需要处理区间 [ l , r ] [l,r] 1 1 的个数是偶数还是奇数。因此我们来定义一下 x r o o t x\rightarrow root d [ x ] d[x] 表示 s u m [ r o o t ] s u m [ x ] sum[root]-sum[x] 的值为奇数还是偶数,即 [ x + 1 , r o o t ] [x+1,root] 1 1 的个数为奇数还是偶数。如果维护的是 [ x , r o o t ] [x,root] 的信息,那么 d [ x ] d[x] 初始值就不确定了,因此维护的是 [ x + 1 , r o o t ] [x+1,root] d [ x ] d[x] 初始为 0 0

所以 x r o o t x\rightarrow root 0 0 ,表示 [ x + 1 , r o o t ] [x+1,root] 1 1 的个数为偶数。如果为 1 1 ,则表示 1 1 的个数为奇数。在合并时维护一个模 2 2 剩余系。

比如 [ x , y ] [x,y] 1 1 的个数为偶数,则 ( x 1 ) y (x-1)\rightarrow y 0 0 f a [ f x ] = f y d [ f x ] = ( x y ) ( x f x ) ( f y y ) = ( 0 d [ x ] + d [ y ] + 2 )   m o d   2 fa[fx] = fy,d[fx] = (x\rightarrow y)-(x\rightarrow fx)-(fy\rightarrow y)=(0-d[x]+d[y]+2)\ mod\ 2

查询 [ x , y ] [x,y] 1 1 个数奇偶,直接 ( d [ x ] d [ y ] + 2 )   m o d   2 (d[x]-d[y]+2)\ mod \ 2 ,为 0 0 则为偶,否则为奇。

至此即可完成本题。

ps:本题也可以维护并查集路径上节点的异或和, 0 0 表示为偶, 1 1 表示为奇。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
typedef long long ll;
typedef double db;
const db EPS = 1e-9;
using namespace std;
const int N = 2*1e4+100;

int n,m,fa[N],d[N],a[N],tot;
struct Query{
	int x,y,op;
}q[N];

int find(int x){
	if(x == fa[x]) return x;
	int root = find(fa[x]);
	d[x] = (d[x]+d[fa[x]]+2)%2;
	return fa[x] = root;
}

int search_for(int x){
	return lower_bound(a+1,a+1+tot,x)-a;
}

int main()
{
	scanf("%d%d",&n,&m); tot = 0;
	rep(i,1,m){
		scanf("%d%d",&q[i].x,&q[i].y);
		char oop[10]; scanf("%s",oop);
		if(oop[0] == 'e') q[i].op = 1;	//偶数
		else q[i].op = 0; //奇数
		a[++tot] = q[i].x-1, a[++tot] = q[i].y;
	}
	sort(a+1,a+1+tot);
	tot = unique(a+1,a+1+tot)-a-1;
	rep(i,0,tot) fa[i] = i, d[i] = 0;
	int ans = m;
	rep(i,1,m){
		int xx = search_for(q[i].x-1), yy = search_for(q[i].y), cc = q[i].op;
		int fx = find(xx), fy = find(yy);
		if(cc){	//偶数
			if(fx != fy){
				fa[fx] = fy;
				d[fx] = (d[yy]-d[xx]+2)%2;
			}
			else{
				int jud = (d[xx]-d[yy]+2)%2;
				if(jud == 1){
					ans = i-1;
					break;
				}
			}
		}
		else { 	//奇数
			if(fx != fy){
				fa[fx] = fy;
				d[fx] = (d[yy]-d[xx]+2+1)%2;
			}
			else{
				int jud = (d[xx]-d[yy]+2)%2;
				if(jud == 0){
					ans = i-1;
					break;
				}
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/88675054
今日推荐