边带权并查集 +离散化 acwing 239

雨燕双飞 提交于 2020-02-06 12:45:46

题意:

一个01序列s,有一些关系l r odd,或者是l r even,分别代表在[l,r]区间内,有奇数个1,有偶数个1.  问最早出现冲突的下标-1.

思路:

用前缀和的思想考虑,l到r的区间,1的个数的奇偶性,就是1~(l-1)的1的个数的奇偶性和1~r的1的个数的奇偶性的关系。

如果sum[l-1]和sum[r]奇偶性相同,那么l到r的1的个数就是偶数,不同就是奇数。

用并查集去维护每个点和祖先的关系,d数组代表和祖先之间的1的个数的奇偶性,偶数为0,奇数为1。

运算规则和异或一样,偶数和偶数为偶数,奇数和奇数为偶数,奇数和偶数为奇数。

合并的时候,x,和y合并。fa[fx]=fy;要计算d[fx]。

x~y的路径:x~fx fx~fy fy~y,x和y的关系a[i].ans=d[x]^d[y]^d[fx]。

d[fx]=d[x]^d[y]^a[i].ans;

#pragma warning(disable:4996)
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<set> 
#include<queue>
using namespace std;
typedef long long ll;
struct node
{
	int l, r, ans;//输入
};
node a[10005];
int fa[20005], d[20005];//d表示和祖先的关系,偶数0,奇数1
vector<int>vec;//用vector来离散化
int find(int x)
{
	if (x == fa[x])return x;
	else
	{
		int t = find(fa[x]);
		d[x] ^= d[fa[x]];//计算和祖先的关系
		return fa[x]=t;
	}
}
int main()
{
	int n, m, i, k;
	int x, y, fx, fy;
	char s[10];
	scanf("%d%d", &n, &m);
	for (i = 1; i <= 2 * m; i++)
	{
		fa[i] = i;
	}
	vec.clear();
	for (i = 1; i <= m; i++)
	{
		scanf("%d%d%s", &a[i].l, &a[i].r, s);
		vec.push_back(a[i].l-1);//前缀和应该是l-1
		vec.push_back(a[i].r);
		if (s[0] == 'o')a[i].ans = 1;//奇数个为1
		else a[i].ans = 0;
	}
	sort(vec.begin(), vec.end());
	vec.erase(unique(vec.begin(), vec.end()), vec.end());
	//排序去重
	for (i = 1; i <= m; i++)
	{
		x = lower_bound(vec.begin(), vec.end(), a[i].l - 1) - vec.begin() + 1;
		y = lower_bound(vec.begin(), vec.end(), a[i].r) - vec.begin() + 1;
		fx = find(x); fy = find(y);
		if (fx == fy)//在一个集合里面
		{
			if ((d[x] ^ d[y]) != a[i].ans)
			//加上括号
			{
				printf("%d\n", i - 1);
				return 0;
			}
		}
		else
		{
			fa[fx] = fy; d[fx] = d[x] ^ d[y] ^ a[i].ans;
			//合并
		}
	}
	printf("%d\n", m);
	return 0;
}

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!