好题,题解来自书
1.设$sum$为前缀异或,$l~r$的奇偶性可以用$sum[r]^sum[l-1]$来表示,1为奇,0为偶
题目转化为给定一些$sum$之间的关系(形如sumi ^ sumj == 1/0),问什么时候出现矛盾
与程序自动分析一题有些相似,但是关系不是简单的相等或不等,而是异或
1.带权并查集(我也不知道怎么想到的
设$d[x]$为边权,0表示与父亲奇偶性相同,在路径压缩时维护,某点到根的边权即为某点到根路径上边权异或的值,合并$x,y$所在的两个集合时,设两个根为$xx,yy$,若让$xx$做$yy$的儿子,他们之间的边权需要由给出的$x,y$的关系决定,即$d[x]^d[xx]^d[y]==q[i].ans$,这样$d[xx]=d[x]^d[y]^q[i].ans$
//#include<bits/stdc++.h> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn=10009; int n,m; struct node{ int l,r,f; }q[maxn]; int hsh[maxn],cnt; int d[maxn*2],fa[maxn*2];//d为边权0为与父亲奇偶性相同 int find(int x){ if(x==fa[x])return x; int rt=find(fa[x]);d[x]^=d[fa[x]]; return fa[x]=rt; } int main(){ scanf("%d%d",&n,&m);char op[10]; for(int i=1;i<=2*m;i++)fa[i]=i; for(int i=1;i<=m;i++) { scanf("%d%d",&q[i].l,&q[i].r); scanf("%s",op); if(op[0]=='e')q[i].f=0; else q[i].f=1; hsh[++cnt]=q[i].l-1;//-1是因为前缀和 hsh[++cnt]=q[i].r; } sort(hsh+1,hsh+1+cnt); cnt=unique(hsh+1,hsh+1+cnt)-hsh-1; for(int i=1;i<=m;i++){ int x=lower_bound(hsh+1,hsh+1+cnt,q[i].l-1)-hsh; int y=lower_bound(hsh+1,hsh+1+cnt,q[i].r)-hsh; int xx=find(x),yy=find(y); if(xx==yy){ if((d[x]^d[y])!=q[i].f){ printf("%d",i-1);return 0; } } else { fa[xx]=yy;d[xx]=d[x]^d[y]^q[i].f; } } printf("%d",m); }
2.扩展域
每个点拆成两个点分别表示这个点是奇数和偶数/1和0,即奇数域和偶数域
根据奇偶性/异或的传递性,若$q[i].ans==1$,就把$x$和$y$的奇点和偶点互相相连,不然就把奇点和奇点,偶点和偶点相连,
代码已钴