acwing 239.奇偶游戏

acwing 239.奇偶游戏

题目链接

题目大意:

有长度为n的01序列,给出m个描述 l , r ,奇/偶 。 表示l~r区间里的1的个数有奇数个或偶数个。问第几个描述与前面的矛盾。输出k - 1;
n:1e9;
m:1e4;

我还是太菜了
做的时候一下就想到了并查集。奇数为1,偶数为0,然后异或就可以。n虽然太大但是m小,可以离散化一下,并不影响。但是想了一下比如1~2 3~4 5~6 怎么把这些并起来。 他们没有相同的数字呀。。。
于是题解告诉我前缀和的思想:设sum[i]表示 i 之前有奇数或偶数个1.l~r区间里奇数或偶数就等于sum[r]^sum[l - 1]。 所以就可以把l - 1;
于是就会做了。

代码:

#include 
#include 
#include 
using namespace std;
std::vector<int> vv;

int getid(int x)
{
	return lower_bound(vv.begin(),vv.end(),x) - vv.begin() + 1;
}
const int maxn = 20005;
int s[maxn];
int l[maxn];
int r[maxn];
int fa[maxn];
int vis[maxn];
void init(int n)
{
	for (int i= 1; i <= n; i ++ )
	{
		fa[i] = i;
		vis[i] = 0;
	}
}
int findx(int x)
{
	if(x == fa[x])
		return x;
	int t = fa[x];
	fa[x] = findx(fa[x]);
	vis[x] ^= vis[t];
	return fa[x];
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for (int  i= 1; i <= m; i ++ )
	{
		char str[5];
		scanf("%d%d%s",&l[i],&r[i],str);
		if(str[0] == 'o')
			s[i] = 1;
		else
			s[i] = 0;
		vv.push_back(l[i]);
		vv.push_back(r[i]);
	}

	sort(vv.begin(),vv.end());
	vv.erase(unique(vv.begin(),vv.end()),vv.end());
	init(vv.size());
	int ans = m + 1;
	for (int i = 1; i <= m; i ++ )
	{
		int x=  getid(l[i] - 1);
		int y=  getid(r[i]);
		int xx = findx(x);
		int yy = findx(y);
		// printf("%d %d %d %d %d\n",xx,yy,vis[x],vis[y],s[i]);
		if(xx == yy)
		{
			if((vis[x] ^ vis[y]) != s[i])
			{
				ans = i;
				break;
			}
		}
		else
		{
			fa[xx] = yy;
			vis[xx] ^= vis[x] ^ vis[y] ^ s[i];
		}
	}
	printf("%d\n",ans - 1);
}

你可能感兴趣的:(做题笔记)