题目链接:洛谷P5937
这道题需要用到种类并查集+离散化+前缀和。
对于100%的数据,1≤N≤109,1≤M≤5×103
因为N有点大,所以我们需要使用到离散化! 来将大数据映射到小范围的小数据。
先前对离散化没有了解的可以学习此篇文章:离 散 化
总得来说离散化有三步走战略:
1.去重(可以用到unique去重函数)
2.排序
3.二分索引(可以用到lower_bound函数)
题解:由于数列中只有0或1,那么使先开一个s数组表示前缀和,那么: s[j]-s[i-1] 是奇数时,则[2 … j]区间中的1的个数为奇数,反之,为偶数。
f[i]存和自己奇偶性相同的集合,f[i+n]存和自己奇偶性不同的集合;
可以根据 奇+奇=偶;偶+偶=偶;奇+偶=奇;来判断一段区间的奇偶性。
#include<bits/stdc++.h>
using namespace std;
#define maxn 5005
struct{
int lc,rc,op;
}a[maxn];
int b[maxn*2],cnt;//离散化
int f[maxn*2];//存祖先
int find(int x){
if(f[x]!=x){
f[x]=find(f[x]);
}
return f[x];
}
void hb(int x,int y){
f[find(x)]=find(y);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
string sh;
cin >> n >> m;
for(int i=1;i<=m;i++){
cin >> a[i].lc >> a[i].rc >> sh;
a[i].lc--;//先--,方便前缀和的计算
if(sh=="even"){
a[i].op=1;//偶数
}else{
a[i].op=0;
}
b[++cnt]=a[i].lc;
b[++cnt]=a[i].rc;
}
sort(b+1,b+cnt+1);
int res=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<=2*res;i++){
f[i]=i;
}
for(int i=1;i<=m;i++){
a[i].lc=lower_bound(b+1,b+res+1,a[i].lc)-b;
a[i].rc=lower_bound(b+1,b+res+1,a[i].rc)-b;
if(a[i].op==1){
//偶数:奇+奇/偶+偶,所以如果(左端点--)后的前缀和和右端点的敌方阵营相同,也就是(左端点--)的前缀和和右端点的奇偶性不同,那么相减后(也就是左端点~右端点)一定为奇数个
if(find(a[i].lc)==find(a[i].rc+res)){
cout << i-1;
return 0;
}else{
hb(a[i].lc,a[i].rc);
hb(a[i].lc+res,a[i].rc+res);
}
}else{
//奇数:奇+偶,同上。
if(find(a[i].lc)==find(a[i].rc)){
cout << i-1;
return 0;
}else{
hb(a[i].lc,a[i].rc+res);
hb(a[i].lc+res,a[i].rc);
}
}
}
cout << m;
return 0;
}