239. 奇偶游戏 AcWing

原题链接

考察:并查集+位运算+前缀和思想+离散化

如果没想到前缀和这题完全没得思路,看了lyd大佬的提示,配合自己画图把这题做出来了= =

思路:

      要AC本题我们需要前缀和思想,如果一个区间内1的个数为even,那么我们可以发现sum[r]-sum[l-1] = 偶,根据奇偶规律,我们可知这两个奇偶性必然相同.同理sum[r]-sum[l-1]为奇,说明两者奇偶不同.而奇偶性又是有传递性的,比如x与y奇偶性相同,而z与y不同,则z与x不同.同理可推得其他推论

      考虑到传递性的奇偶性,以及前面的例题食物链,我们可以利用奇偶的传递性判断问题的真假.利用与根结点的奇偶性关系即可.与食物链那题不同的是,我们在那题需要维护距离数组,而本题是维护奇偶性数组,d[x]表示与父节点奇偶性的关系.我们可以发现利用异或可以很容易得到与父节点的父节点的奇偶性的关系.因此我们只需要将findf函数里的距离累加换成距离累异或即可.

 

2021.5.13 补一个带扩展域并查集的思路.

      带扩展域并查集,x并不代表它自己,而是一个条件.我们设定 x表示x为偶数,x+n表示 x为奇数. 我们并查集合并是合并条件:只要在一个集合里的有一个条件成立,那么整个集合里的条件都成立.如果x y even 说明 x与y的类别相同,此时我们合并x y, x+n与y+n 合并.

      如何判断矛盾呢?当 x y even时,x+n与y在同意集合就出现了矛盾.

     注意这里n要正确取值.否则x,y可能与x+n,y+n发生冲突.这里我们离散化后在+n就不易冲突,x+n没必要离散化.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 20010;
 4 struct query{
 5     int l,r,ans; 
 6 }query[N/2];
 7 vector<int> alls;
 8 int p[N],d[N];//d数组用来记录与父节点奇偶的关系 
 9 int findid(int x)
10 {
11     return lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1;
12 }
13 int findf(int x)
14 {
15     if(x!=p[x]){
16         int t = findf(p[x]);
17         d[x]^=d[p[x]];
18         p[x] = t;
19     }
20     return p[x];
21 }
22 int main()
23 {
24     int n,m;
25     bool flag = true;
26     scanf("%d%d",&n,&m);
27     for(int i=1;i<=m;i++){
28         char op[10];
29         scanf("%d%d%s",&query[i].l,&query[i].r,op);
30         if(op[0]=='e') query[i].ans = 0;
31         else query[i].ans = 1;
32         alls.push_back(query[i].l-1); alls.push_back(query[i].r);
33     }
34     sort(alls.begin(),alls.end());
35     alls.erase(unique(alls.begin(),alls.end()),alls.end());
36     for(int i=1;i<=alls.size();i++) p[i] = i;
37     for(int i=1;i<=m;i++){
38         int x = findid(query[i].l-1); int y = findid(query[i].r);
39         int px = findf(x); int py = findf(y);
40         if(px!=py){//并入集合 
41             d[py] = query[i].ans^d[x]^d[y];
42             p[py] = px;
43         }else if(px==py&&(d[x]^d[y])!=query[i].ans){
44             flag = false;
45             printf("%d\n",i-1); break;
46         }
47     }
48     if(flag) printf("%d\n",m);
49     return 0;
50 } 

 

posted @ 2021-01-04 01:21  acmloser  阅读(199)  评论(0编辑  收藏  举报