题目:POJ1733.
题目大意:给定
n
n
n个区间
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]和
a
i
a_i
ai,表示
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]的权值和为奇数或偶数,问到哪一个区间不矛盾,但它的下一个区间矛盾.
1
≤
n
≤
5
∗
1
0
3
1\leq n\leq 5*10^3
1≤n≤5∗103.
容易想到前缀和,那么区间就变成了两个点 l i − 1 l_i-1 li−1和 r i r_i ri上的信息.
考虑用带权并查集维护每个点的前缀和 d [ i ] d[i] d[i],一个点 i i i的点权表示 i i i的前缀和异或 i i i的父亲的点权,即区间 [ f a [ i ] + 1 , i ] [fa[i]+1,i] [fa[i]+1,i]的奇偶性.
加入一个区间 [ l i , r i ] [l_i,r_i] [li,ri]时若 l i − 1 , r i l_i-1,r_i li−1,ri在同一个区间就大力判断它们点权异或是否等于 a [ i ] a[i] a[i].然后加入这个区间就相当于把 r i r_i ri的祖先设为 l i − 1 l_i-1 li−1,并同时更新点权.
注意这个时候路径压缩时也要更新点权.
时间复杂度 O ( n log n ) O(n\log n) O(nlogn).
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=5000;
int ri(){
char c=getchar();
int x=0,y=1;
for (;c<'0'||c>'9';c=getchar()) if (c=='-') y=-1;
for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
return x*y;
}
int rc(){
char c=getchar();
while (c<'a'||c>'z') c=getchar();
return c=='o'?1:0;
}
int n,ord[N*2+9],x[N+9],y[N+9],a[N+9];
int fa[N*2+9],d[N*2+9],ans;
int lower(int k){
int l=1,r=n<<1,mid=l+r>>1;
for (;l<r;mid=l+r>>1)
k<=ord[mid]?r=mid:l=mid+1;
return l;
}
int get(int u){
if (u==fa[u]) return u;
int rot=get(fa[u]);d[u]^=d[fa[u]];
return fa[u]=rot;
}
Abigail into(){
ri();n=ri();
for (int i=1;i<=n;++i){
x[i]=ri()-1;y[i]=ri();a[i]=rc();
ord[i*2-1]=x[i];ord[i*2]=y[i];
}
}
Abigail work(){
sort(ord+1,ord+1+2*n);
for (int i=0;i<=n;++i)
x[i]=lower(x[i]),y[i]=lower(y[i]);
for (int i=1;i<=n<<1;++i) fa[i]=i;
int u,v;
ans=n;
for (int i=1;i<=n;++i){
u=get(x[i]);v=get(y[i]);
if (u==v&&d[x[i]]^d[y[i]]^a[i]){ans=i-1;return;}
fa[v]=u,d[v]=d[x[i]]^d[y[i]]^a[i];
}
}
Abigail outo(){
printf("%d\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}