【SSL】1227 &【洛谷】P5937A Parity game

【SSL】1227 &【洛谷】P5937A Parity game

Time Limit:1000MS
Memory Limit:65536K

题目描述

Alice 和 Bob 在玩一个游戏:他写一个由 0 和 1 组成的序列。Alice 选其中的一段(比如第 3 位到第 5 位),问他这段里面有奇数个 1 还是偶数个 1。Bob 回答你的问题,然后 Alice 继续问。Alice 要检查 Bob 的答案,指出在 Bob 的第几个回答一定有问题。有问题的意思就是存在一个 01 序列满足这个回答前的所有回答,而且不存在序列满足这个回答前的所有回答及这个回答。

输入格式

第 1 行一个整数 n,是这个 01 序列的长度。

第 2 行一个整数 m,是问题和答案的个数。

第 3 行开始是问题和答案,每行先有两个整数,表示你询问的段的开始位置和结束位置。然后是 Bob 的回答。odd表示有奇数个 1,even 表示有偶数个 1。

输出格式

输出一行,一个数 x,表示存在一个 01 序列满足第 1 到第 x 个回答,但是不存在序列满足第 1 到第 x+1个回答。如果所有回答都没问题,你就输出所有回答的个数。

输入输出样例

输入
10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd
输出
3

说明/提示

对于 100% 的数据, 1 ≤ n ≤ 1 0 9 , m ≤ 5 × 1 0 3 1 \le n \leq 10^9 ,m \leq 5 \times 10^3 1n109m5×103

思路

并查集扩展域,
n,n本身,奇偶性相同的域
n+tot,奇偶性不同的域
排序,去重,节省空间。
边奇数:x-1与y奇偶性不同,f[find(x-1)]=find(y+tot);f[find(x-1+tot)]=find(y);
边偶数:x-1与y奇偶性相同,f[find(x-1)]=find(y);f[find(x-1+tot)]=find(y+tot);

从整个01序列肯定是无法入手的,因为它的长度高达109。
从范围比较小的n入手。也就是说我们需要对信息进行一些特殊的处理。
a b even/odd,那么将元素b指向a-1,边的权值是even/odd。
下面我们由样例来说明一下这个处理方法。
在这里插入图片描述

显然在第4条信息加入的时候,6到0已经有值存在,即(0+1+0)mod 2=1,这时添入6到0为0显然是不对。
实现的时候不用开1-109的数组,因为出现的不同元素最多有104而已,因此,开一个列表存储元素即可。
算法的大致框架就是对于读入的信息不断地用上述方法处理,由区间的递推性质可以得出矛盾与否。
上述算法的实现就用到了并查集。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int f[10010]/*n,n本身,奇偶性相同的域,n+tot,奇偶性不同的域*/,a[10010],tot=0;
struct jgt
{
    
    
	int x,y,w;
}b[5010];
int find(int x)//找代表值 
{
    
    
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
int effind(int x)//二分查找 
{
    
    
	int l,r,mid;
	for(l=1,r=tot;l<r;)
	{
    
    
		mid=(l+r)/2;
		if(x>a[mid]) l=mid+1;
		else r=mid;
	}
	return r;
}
int main()
{
    
    
	char str[10];
	int n,m,j,i,t,x,y,ans=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
    
    
		scanf("%d%d%s",&b[i].x,&b[i].y,&str);
		b[i].x--; 
		b[i].w=(str[0]=='o');
		a[++tot]=b[i].x;
		a[++tot]=b[i].y;
	}
	sort(a+1,a+1+tot);//排序 
	for(i=2,j=1;i<=tot;i++)//去重,节约空间 
		if(a[i]!=a[i-1])
			a[++j]=a[i];
	tot=j;
	for(i=1;i<=2*tot;f[i]=i,i++);//初始化
	for(i=1;i<=m;i++)
	{
    
    
		x=effind(b[i].x),y=effind(b[i].y);
		if(b[i].w)//奇数 
		{
    
    
			if(find(x)==find(y))
			{
    
    
				printf("%d",i-1);
				return 0;
			}
			else f[find(x)]=find(y+tot),f[find(x+tot)]=find(y);//合并 
		}
		else//偶数 
		{
    
    
			if(find(x)==find(y+tot))
			{
    
    
				printf("%d",i-1);
				return 0;
			}
			else f[find(x)]=find(y),f[find(x+tot)]=find(y+tot);//合并 
		}
	}
	printf("%d",m);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_46975572/article/details/113004259