一道特别玄学的题
Description
你偶尔和朋友玩如下的游戏。你的朋友写下一个由01组成的序列。你选择连续的一段子序列(例如,从第3到第5个数的子序列),问他这一段中1的个数是偶数还是奇数。你的朋友会回答你的问题,然后你可以问他另外一段子序列,等等。你的任务是猜出整个序列。
你怀疑你朋友的一些回答可能是错误的,并且你希望证明他说了假话。因此你决定写一个程序来帮助你。这个程序将会收到你的一系列问题以及你朋友给出的答案。程序的目标是找到第一个被证明是错误的回答,即,存在一个序列能满足之前所有回答,但加上这个回答后就不存在相应的序列。
Input
第一行有一个整数,代表01序列的长度。长度不超过1000000000。
第二行有一个正整数,代表询问和回答的数量。数量不超过5000.
接下来的若干行描述了所有的了询问和回答。每一行包含了一个询问和对此询问的回答:两个整数(所选择的子序列的起止点),一个单词“even”或“odd”(答案,即该子序列中1的个数的奇偶性),其中“even”代表有偶数个,“odd”代表有奇数个。
Output
输出一个整数X。它意味着:存在一个01序列满足前X个奇偶性询问,但不存在满足前X+1个奇偶性询问的序列。如果存在满足所有询问的序列,X就应该是询问的总数。
Sample Input
输入样例1:
10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd
输入样例2:
10
5
1 2 even
1 4 even
2 4 odd
1 10 even
3 10 even
1 2 even
Sample Output
输出样例1:
3
输出样例2:
5
首先离散化一下(把没有出现过的点全看做偶数,于是可以直接X掉)
然后连边
对于每个询问Q(a,b,c)(c为even或odd)
在a,b间连一条权值为c的边(even==0,odd==1)
但这时发现,如果1,2为even,3,4为even,那么1,4就已经知道是even了
然而程序里得不到体现,
于是将“在a,b间连一条权值为c的边”改成“在a-1,b间连一条权值为c的边”
然后惊喜的发现0,4联通了!!!
需要注意的是,如果图上有环,就说明朋友的话可能会起冲突了,
打表证明:如果环上边权值和为even,则不起冲突,反之起冲突
用并查集维护两点是否联通,如果两点联通时要连边,则取消,判断这两点之间的路径权值之和
与这条要加的边权值相加再判断即可
这样保证了图是一棵树,因为数据水,判断环上权值和可以直接暴力!!!
水过!!!!!!
#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=10002,maxm=10002;
int fir[maxn],dis[maxn],nxt[maxn],id=1,w[maxn];
#define il inline
#define vd void
#define t (dis[i])
il int gi(int x=0){
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
il vd add(int a,int b,int c){
nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c;
}
int Qa[5111],Qb[5111],Qc[5111],nums[11111],k=0;
char str[10];
map<int,int>m;
int fa[maxn];
il int hd(int now){
if(fa[now]^now)fa[now]=hd(fa[now]);
return fa[now];
}
il int dfs(int now,int final,int fa,int num){
if(now==final)return num&1;
for(int i=fir[now];i;i=nxt[i])
if(t!=fa){
int kk=dfs(t,final,now,num^w[i]);
if(kk!=-1)return kk;
}
return -1;
}
int main(){
int n=gi(),q=gi();
for(int i=1;i<=q;i++){
Qa[i]=gi()-1,Qb[i]=gi(),scanf("%s",str);
if(str[0]=='o')Qc[i]=1;
else Qc[i]=0;
nums[++k]=Qa[i],nums[++k]=Qb[i];
}
sort(nums+1,nums+q+q+1);
int s=0;
for(int i=1;i<=q<<1;i++)if(nums[i]!=nums[i-1])m[nums[i]]=++s;
for(int i=1;i<=s;i++)fa[i]=i;
for(int hehehe=1;hehehe<=q;hehehe++){
int a=m[Qa[hehehe]],b=m[Qb[hehehe]],c=Qc[hehehe];
if(hd(a)!=hd(b))fa[hd(a)]=hd(b),add(a,b,c),add(b,a,c);
else if(dfs(a,b,-1,0)!=c){printf("%d\n",hehehe-1);return 0;}
}printf("%d\n",q);
return 0;
}