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函数里的距离累加换成距离累异或即可
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 }
标签:奇偶,int,sum,奇偶性,传递性,alls,239,AcWing 来源: https://www.cnblogs.com/newblg/p/14227650.html