题意:有一个 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\n",M[a[i]],M[b[i]],v[i]);
62     }
63     for(i=1;i<=cnt;i++){
64         printf("%d %d %d\n",i,fa[i],num[i]);
65     }*/
66     printf("%d\n",ans);
67     return 0;
68 }
View Code