思路
先求一遍前缀和 设每次询问为 l,r,ans 由前缀和的性质我们知道 ,
如果 sum[l~r]=‘odd’ 说明 sum[r]和sum[l-1] 的奇偶性不同,一奇一偶,否则说明两者奇偶性相同,同为奇数或者同为偶数。
这题我们考虑带权并查集
设边权d[x]为0,表示x和fa[x]的奇偶性相同,如果d[x]为1,表示x和fa[x]的奇偶性不同 在进行路径压缩时,对x到树根的所有边权做异或运算,可以得到x和树根的关系
对每个询问,设ans表示该问题的回答(0代表偶 1代表奇)
先检查x和y是否在同一个集合内,(奇偶关系是否已知) 如果在同一个集合内 并且d[x]^d[y]!=ans 则该关系和回答矛盾,可以确定撒慌
否则合并x和y的两个集合,设两个集合的树根分别为x1和y1,令fa[x1]=y1, 已知d[x],d[y]分别表示路径x与x1, y 与y1 的奇偶性,x~y之间的奇偶性为ans,显然ans=d[x]^ d[y] ^d[x1],所以,d[x1]=ans ^ d[x] ^d[y]
最后,因为n的范围为1e9,数组开不了这么大的范围,所以我们需要对l-1和r,这两个点进行离散化
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include <cstring>
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> PII;
int d[maxn];
int fa[maxn];
int a[maxn];
int t;
struct query
{
int l,r,ans;
}qr[maxn];
int find(int x)
{
if(x==fa[x])
return x;
int f=fa[x];
fa[x]=find(fa[x]);
d[x]^=d[f];
return fa[x];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
char ch[5];
cin>>qr[i].l>>qr[i].r>>ch;
qr[i].ans=(ch[0]=='o'?1:0);
a[++t]=qr[i].l-1;
a[++t]=qr[i].r;
}
sort(a+1,a+1+t);
n=unique(a+1,a+1+t)-a-1;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=lower_bound(a+1,a+1+n,qr[i].l-1)-a;
int y=lower_bound(a+1,a+1+n,qr[i].r)-a;
int x1=find(x),y1=find(y);
if(x1==y1)
{
if((d[x]^d[y])!=qr[i].ans)
{
cout<<i-1<<endl;
return 0;
}
}
else
{
fa[x1]=y1;
d[x1]=qr[i].ans^d[x]^d[y];
}
}
cout<<m<<endl;
}