P5937 [CEOI 1999] Parity Game 题解
P5937 [CEOI 1999] Parity Game - 洛谷
差分数组+并查集(拓展域) + 离散化
差分数组思想:
区间个数——> 前缀和 转化为 差分数组 求区间就变为 num = pre[r] - pre[l-1] 。
当num 为奇数: pre[l-1] 和 pre[r] 异号
当num为偶数时:同号
我们只看下标,来代替pre
并查集只存同号的数 , 将同号的数划为一个集合。前面存原本的数x,x+len是x对立面。
奇数对立面为偶数 , 反之如此。
看注释 , 要搞清楚 ll 和 rr 在奇数偶数时的关系
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;int father[N];void build(int n)
{for(int i=0;i<=n;i++){father[i] = i;}
}int f(int x)
{if(x != father[x]){father[x] = f(father[x]);}return father[x];
}int main()
{int n,m;cin>>n>>m;vector<int> alls;vector<vector<int>> nums(m,vector<int>(3));for(int i=0;i<m;i++){string op;cin>>nums[i][0]>>nums[i][1]>>op;if(op == "even"){ //偶数0nums[i][2] = 0;}else{ //奇数1nums[i][2] = 1;}//差分数组区间 l-1 , ralls.push_back(nums[i][0]-1);alls.push_back(nums[i][1]);}//离散化sort(alls.begin() , alls.end()); //排序alls.erase(unique(alls.begin() , alls.end()) , alls.end()); //去重int len = alls.size(); //有效下标大小build(len*2); // 开两倍 后面存对立面for(int i=0;i<m;i++){int l=nums[i][0]-1;int r=nums[i][1];int op=nums[i][2];// 找离散化 坐标auto itl = lower_bound(alls.begin() , alls.end() , l);int ll = itl - alls.begin();auto itr = lower_bound(alls.begin() , alls.end() , r);int rr = itr - alls.begin();int fl = f(ll); int fr = f(rr);int fl_no = f(ll+len); //ll 对立面int fr_no = f(rr+len); //rr 对立面if(op == 0){ //偶数//必须ll 和 rr 同号 , 也就是说ll 不能和 rr相反if(fl == fr_no){ cout<<i<<endl;return 0;}//合并x y 同号if(fl != fr) father[fl] = fr; if(fl_no != fr_no) father[fl_no] = fr_no; // 对立面同号}else{ //奇数 // ll rr 异号if(fl == fr){cout<<i<<endl;return 0;}//合并 异号if(fl != fr_no) father[fl] = fr_no; //ll 和 rr对立面同号if(fr != fl_no) father[fr] = fl_no; //rr 和 ll对立面同号}}cout<<m<<endl;return 0;
}