题目链接:poj 1733
先求一遍前缀和 设每次询问为 l,r,ans 由前缀和的性质我们知道
如果 ans='odd' 说明 sum[r]和sum[l-1] 的奇偶性不同,否则说明两者奇偶性相同
第一种方法是边带权,边权d[x]为0,表示x和fa[x]的奇偶性相同,如果d[x]为1,表示x和fa[x]的奇偶性不同 在进行路径压缩时,对x到树根的所有边权做异或运算,可以得到x和树根的关系
对每个询问,设离散化后l-1,r的值分别是x和y,设ans表示该问题的回答(0代表偶 1代表奇)
- 先检查x和y是否在同一个集合内,(奇偶关系是否已知) 如果在同一个集合内 并且d[x]^d[y]!=ans 则该关系和回答矛盾,可以确定撒慌
- 否则合并x和y的两个集合,设两个集合的树根分别为p和q,令fa[p]=q, 已知d[x],d[y]分别表示路径x~p,y~q之间所有边权的"xor和",p~q之间的边权d[p]是待求得值。 显然路径x~y由路径x~p,p~q,q~y组成,因此x与y得奇偶性关系 ans=d[x]^d[y]^d[p] 所以 d[p]=d[x]^d[y]^ans
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10010;
struct Query{
int l,r,ans;
}qr[N];
int a[N*2],fa[N*2],d[N*2],n,m,t;
int get(int x){
if(x==fa[x]) return x;
int rt=get(fa[x]);d[x]^=d[fa[x]];
return fa[x]=rt;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; i++){
char str[5];
scanf("%d%d%s",&qr[i].l,&qr[i].r,str);
qr[i].ans=(str[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 p = get(x),q = get(y);
if(p==q){
if((d[x]^d[y])!=qr[i].ans){
printf("%d\n",i-1);
return 0;
}
}else{
fa[p]=q;d[p]=qr[i].ans^d[x]^d[y];
}
}
printf("%d\n",m);
return 0;
}
第二种方法是扩展域的方法,把每个变量x拆成两个结点
和
,分别表示前缀和 sum[x]是奇数和sum[x]是偶数,称为奇数域和偶数域
- 如果ans=0,则合并Xodd和Yodd,Xeven和Yeven,这表示x为奇数与y为奇数,x为偶数与y为偶数可以相互推导出
- 否则,合并Xodd和Yeven,Xeven和Yodd,这表示x为奇数和y为偶数,x为偶数y为奇数可以相互推导出
- 在上述合并前得检查ans是否和已知的信息冲突
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 20010;
struct Query{
int l,r,ans;
}qr[N];
int a[N*2],fa[N*2],n,m,t;
int get(int x){
if(x==fa[x]) return x;
return fa[x]=get(fa[x]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; i++){
char str[5];
scanf("%d%d%s",&qr[i].l,&qr[i].r,str);
qr[i].ans=(str[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 <= 2*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 xo = x,xe = x+n,yo = y,ye = y+n;
if(qr[i].ans){
if(get(xo)==get(yo)){
printf("%d\n",i-1);
return 0;
}
fa[get(xo)]=get(ye),fa[get(xe)]=get(yo);
}else{
if(get(xe)==get(yo)){
printf("%d\n",i-1);
return 0;
}
fa[get(xo)]=get(yo),fa[get(xe)]=get(ye);
}
}
printf("%d\n",m);
return 0;
}