题意:有一个 0/1 数列,现在有n组询问和回答,表示某个区间内有奇数或者偶数个1,问到前多少个都没有逻辑错误,而下一个就不满足
可以定奇数为 1 偶数为 0作为每个元素的权值,表示它与它的祖先元素的差距,这样通过 mod2 可以直接表示两奇或两偶都得偶,奇偶得奇,然后就是对前序1的个数和做并查集的操作,注意对于一个区间[a,b],合并的两个元素是 a-1 和 b 。直到找到错误就可以了。由于区间太大,可以离散化各个需要合并的元素,再离线操作并查集。
1 #include<stdio.h>
2 #include<string.h>
3 #include<map>
4 using namespace std;
5
6 int fa[10005],n,m,num[10005],a[5005],b[5005],v[5005];
7 char s[10];
8
9 void init(){
10 for(int i=0;i<=10000;i++)fa[i]=i;
11 memset(num,0,sizeof(num));
12 }
13
14 int find(int x){
15 int r=x,c=0,t1,t2;
16 while(r!=fa[r]){
17 c+=num[r];
18 r=fa[r];
19 }
20 while(x!=r){
21 t1=fa[x];
22 t2=c-num[x];
23 fa[x]=r;
24 num[x]=c%2;
25 x=t1;
26 c=t2;
27 }
28 return r;
29 }
30
31 int main(){
32 scanf("%d%d",&n,&m);
33 init();
34 int i,cnt=0,ans=0;
35 map<int,int>M;
36 for(i=1;i<=m;i++){
37 scanf("%d%d%s",&a[i],&b[i],s);
38 a[i]--;
39 if(s[0]=='e')v[i]=0;
40 else v[i]=1;
41 if(!M[a[i]])M[a[i]]=++cnt;
42 if(!M[b[i]])M[b[i]]=++cnt;
43 }
44 bool f=1;
45 for(i=1;i<=m;i++){
46 int x=find(M[a[i]]),y=find(M[b[i]]);
47 if(x!=y){
48 num[x]=((num[M[b[i]]]+v[i]-num[M[a[i]]])%2+2)%2;
49 fa[x]=y;
50 if(f)ans++;
51 }
52 else{
53 if(f){
54 if(!v[i]&&num[M[a[i]]]==num[M[b[i]]])ans++;
55 else if(v[i]&&num[M[a[i]]]!=num[M[b[i]]])ans++;
56 else f=0;
57 }
58 }
59 }/*
60 for(i=1;i<=m;i++){
61 printf("%d %d %d
",M[a[i]],M[b[i]],v[i]);
62 }
63 for(i=1;i<=cnt;i++){
64 printf("%d %d %d
",i,fa[i],num[i]);
65 }*/
66 printf("%d
",ans);
67 return 0;
68 }