POJ (貌似不支持c++11和万能头)
AcWing (都支持)
奇偶游戏
1、当区间 [a,b] 内有奇数个1,那么前缀和S[b] - S[a-1] 为奇数,意味着S[b]与S[a-1]奇偶性不同。(可用其坐标代替前缀和表示相对关系)
2、当区间 [a,b] 内有偶数个1,那么前缀和S[b] - S[a-1] 为偶数,意味着S[b] 与S[a-1] 奇偶性相同。
前缀和分为两类——奇数、偶数,通过区间的奇偶性我们能获得 M 对点的相对关系 (奇偶性是否相同),当出现当前的关系与之前的关系冲突时,即为谎话。例如 a 与 b奇偶性不同,b与c奇偶性相同,那么如果出现一对关系 a与c奇偶性相同,即为谎话。
所以我们可以使用带权并查集,通过维护每个点到根的距离表示某种关系,进而判断任意两点之间的关系,从而判断是否产生冲突;(模2意义下到根节点距离:0代表奇偶性相同,1代表不同)
#include<iostream>
#include<string>
#include<unordered_map>
using namespace std;
const int N = 20010;
int p[N],n,m;
int d[N]; // d[x] 代表 x 到p[x] 的距离;(压缩路径后p[x] 会存根节点)
unordered_map<int,int> mp;
int get(int x){ //无序离散化
if(mp[x]==0) mp[x] = ++n;
return mp[x];
}
int find(int x){
if(p[x]!=x) {
int r = find(p[x]);
d[x] += d[p[x]];
p[x] = r;
}
return p[x];
}
int main()
{
cin>>n>>m;
n=0;
int ans = m;
for(int i=1;i<N;i++) p[i] = i;
for(int i=1;i<=m;i++){
int a,b;
string s;
cin>>a>>b>>s;
a = get(a-1),b = get(b);
int t = 0;
if(s=="odd") t = 1;
int pa = find(a),pb = find(b);
if(pa==pb){
if(t==1){
if(d[a]%2==d[b]%2) {
ans = i-1;break;
}
}
else {
if(d[a]%2!=d[b]%2) {
ans = i-1;break;
}
}
}
else {
p[pa] = pb;
d[pa] = (d[a]+d[b]+t)%2; //在模2的意义下的加法可以用^代替 例如:(a+b)%2 相当于a^b;
}
}
cout<<ans<<endl;
return 0;
}