【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 1≤n≤109,m≤5×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;
}