题意:
一个长度为
的由
和
组成的序列
。
个询问,返回
中
的个数是奇数还是偶数。输出一个最小的
,使得存在一个
序列满足第
个回答,但不存在满足第
个回答的
序列。
思路:
比较大,但是询问比较少,因此需要将所有数字离散化。
然后我们需要处理区间 的 的个数是偶数还是奇数。因此我们来定义一下 , 表示 的值为奇数还是偶数,即 中 的个数为奇数还是偶数。如果维护的是 的信息,那么 初始值就不确定了,因此维护的是 , 初始为 。
所以 为 ,表示 中 的个数为偶数。如果为 ,则表示 的个数为奇数。在合并时维护一个模 剩余系。
比如 中 的个数为偶数,则 为 , 。
查询 中 个数奇偶,直接 ,为 则为偶,否则为奇。
至此即可完成本题。
ps:本题也可以维护并查集路径上节点的异或和, 表示为偶, 表示为奇。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
typedef long long ll;
typedef double db;
const db EPS = 1e-9;
using namespace std;
const int N = 2*1e4+100;
int n,m,fa[N],d[N],a[N],tot;
struct Query{
int x,y,op;
}q[N];
int find(int x){
if(x == fa[x]) return x;
int root = find(fa[x]);
d[x] = (d[x]+d[fa[x]]+2)%2;
return fa[x] = root;
}
int search_for(int x){
return lower_bound(a+1,a+1+tot,x)-a;
}
int main()
{
scanf("%d%d",&n,&m); tot = 0;
rep(i,1,m){
scanf("%d%d",&q[i].x,&q[i].y);
char oop[10]; scanf("%s",oop);
if(oop[0] == 'e') q[i].op = 1; //偶数
else q[i].op = 0; //奇数
a[++tot] = q[i].x-1, a[++tot] = q[i].y;
}
sort(a+1,a+1+tot);
tot = unique(a+1,a+1+tot)-a-1;
rep(i,0,tot) fa[i] = i, d[i] = 0;
int ans = m;
rep(i,1,m){
int xx = search_for(q[i].x-1), yy = search_for(q[i].y), cc = q[i].op;
int fx = find(xx), fy = find(yy);
if(cc){ //偶数
if(fx != fy){
fa[fx] = fy;
d[fx] = (d[yy]-d[xx]+2)%2;
}
else{
int jud = (d[xx]-d[yy]+2)%2;
if(jud == 1){
ans = i-1;
break;
}
}
}
else { //奇数
if(fx != fy){
fa[fx] = fy;
d[fx] = (d[yy]-d[xx]+2+1)%2;
}
else{
int jud = (d[xx]-d[yy]+2)%2;
if(jud == 0){
ans = i-1;
break;
}
}
}
}
printf("%d\n",ans);
return 0;
}