题目描述
Tom和Bob在玩一个游戏:他写一个由0和1组成的序列。
Tom选其中的一段(比如第3位到第5位),问他这段里面有奇数个1还是偶数个1。Bob回答你的问题,然后Tom继续问。
Bob有可能在撒谎。Tom要检查Bob的答案,指出在Bob的第几个回答一定有问题。
有问题的意思就是存在一个01序列满足这个回答前的所有回答,而且不存在序列满足这个回答前的所有回答及这个回答。
输入
第1行一个整数,是这个01序列的长度(<=1000000000)
第2行一个整数,是问题和答案的个数。
第3行开始是问题和答案,每行先有两个整数,表示你询问的段的开始位置和结束位置。
然后是Bob的回答。odd表示有奇数个1,even表示有偶数个1。
输出
输出一行,一个数X,表示存在一个01序列满足第1到第X个回答,但是不存在序列满足第1到第X+1个回答。如果所有回答都没问题,你就输出所有回答的个数。
样例输入
样例输出
提示
第4条与之前有矛盾,前3条没问题
最多10000个问题
乍一看,我们的心中就涌出一股熟悉感——发现和《谁在说谎》很像,于是我们就会想到这不是水题吗?关系类并查集啊。
可是再乍一看这道题的数据范围,发现数据范围非常诡异。n居然有10^9!感觉日了狗了。。。
尼玛,这怎么开数组,你在逗我……
可是我们再乍一看,发现m的范围非常正常(心中涌出一股感激之情)。我们一霎那(十分钟)就想到了离散化这种好东西。
有了它,我们可以秒过这种难倒ty大婶的水题。(ty冲了过来)
我们发现这道题可以将相邻的点给合并,但是我们将数组离散化之后就没法判断是否相邻了,怎么办呢,我们需要请教ty大婶(ty摔了一跤).
口胡,并查集先生可以轻松妙杀ty(掏出Mr并查集,ty惊恐地爆0了,^_^)
咳咳,我们发现其实当区间相邻时,可以利用另外一个性质,它们的首尾端点相同!
我们只要不记格子,直接记端点即可.
轻松秒过啊.(ty:我不服!!Mr并查集:一砖排飞)
这里附代码(温馨提示,为防止某人不劳而获,我把程序修改了一下)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using
namespace
std;
long
long
n,m,x,y,t,dis[100005],f[100005];
char
st[100000];
struct
node
{
long
long
xx,yy,zz;
}a[100005],b[100005];
bool
cmp(node x,node y)
{
return
x.xx<y.xx;
}
long
long
find(
long
long
root)
{
if
(root==f[root])
return
root;
long
long
t=f[root];
f[root]=find(f[root]);
dis[root]+=dis[t];
return
f[root];
}
int
main()
{
cin>>n;
cin>>m;
for
(
int
i=1;i<=m;++i)
{
cin>>x>>y;
cin>>st;
if
(st[0]==
'e'
) t=0;
else
t=1;
x--;
a[i+i-1].xx=x;a[i+i].xx=y;
a[i+i-1].yy=i+i-1;a[i+i].yy=i+i;
a[i+i-1].zz=t;a[i+i].zz=t;
}
sort(a+1,a+1+m+m,cmp);
//for (int i=1;i<=m+m;++i) cout<<a[i].xx<<' ';cout<<endl;
t=0;
for
(
int
i=1;i<=m+m;++i)
{
if
(a[i].xx!=a[i-1].xx) ++t;
if
(a[i].yy & 1) b[(a[i].yy+1)/2].xx=t,b[(a[i].yy+1)/2].zz=a[i].zz;
else
b[a[i].yy/2].yy=t,b[a[i].yy/2].zz=a[i].zz;
}
//for (int i=1;i<=m;++i) cout<<b[i].xx<<' '<<b[i].yy<<' '<<b[i].zz<<endl;
n=t;
for
(
int
i=1;i<=n;++i) f[i]=(
long
long
)(i);
memset
(dis,0LL,
sizeof
(dis));
for
(
int
i=1;i<=m;++i)
{
x=find(b[i].xx),y=find(b[i].yy);
if
(x==y)
{
if
(((dis[b[i].xx]+dis[b[i].yy])&1) != b[i].zz) {cout<<i-1<<endl;
return
0;}
continue
;
}
else
{
f[y]=x;
dis[y]=(b[i].zz+dis[b[i].yy]+dis[b[i].xx])&1;
}
}
cout<<m<<endl;
return
0;
}
|
题目不要乍一看,要乍三看。
有时记端点比记坐标来的方便。