Tom和Bob在玩一个游戏:他写一个由0和1组成的序列。
Tom选其中的一段(比如第3位到第5位),问他这段里面有奇数个1还是偶数个1。Bob回答你的问题,然后Tom继续问。
Bob有可能在撒谎。Tom要检查Bob的答案,指出在Bob的第几个回答一定有问题。
有问题的意思就是存在一个01序列满足这个回答前的所有回答,而且不存在序列满足这个回答前的所有回答及这个回答。
标签:
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个回答。如果所有回答都没问题,你就输出所有回答的个数。
10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd
3
【样例说明】
第4条与之前有矛盾,前3条没问题
【数据规模和约定】
最多10000个问题
经典并查集
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; int n,m,len; int a[10005],b[10005],t[10005],c[21000],p[21000]; int f[21000],dis[21000]; char s[10]; int erfen(int l,int r,int s) { int mid=(l+r)/2; if(s==p[mid]) return mid; if(s>p[mid]) return erfen(mid+1,r,s); if(s<p[mid]) return erfen(l,mid-1,s); } int get(int x) { if(f[x]==x) return x; int t=f[x]; f[x]=get(f[x]); dis[x]=(dis[x]+dis[t])%2; return f[x]; } int main() { cin>>n>>m; for(int i=1;i<=m;i++) { scanf("%d%d%s",&a[i],&b[i],s+1); a[i]--; c[i*2-1]=a[i]; c[i*2]=b[i]; if(s[1]=='e') t[i]=0;else t[i]=1; } sort(c+1,c+2*m+1); int x=-1; for(int i=1;i<=2*m;i++) if(c[i]!=x) { len++; p[len]=c[i]; x=c[i]; } for(int i=1;i<=len;i++) { f[i]=i; dis[i]=0; } for(int i=1;i<=m;i++) { int x=erfen(1,len,a[i]); int y=erfen(1,len,b[i]); int u=get(x); int v=get(y); if(u==v) { if(t[i]==0) { if(dis[x]!=dis[y]) { cout<<i-1<<endl; return 0; } } else { if(dis[x]==dis[y]) { cout<<i-1<<endl; return 0; } } } else { f[v]=u; if(t[i]==0) { if(dis[x]!=dis[y]) dis[v]=(dis[v]+1)%2; } else { if(dis[x]==dis[y]) dis[v]=(dis[v]+1)%2; } } } cout<<m<<endl; return 0; }
标签:
原文地址:http://blog.csdn.net/donald_ty/article/details/51335214