题解 P5937 【[CEOI1999]Parity Game】
这道题有两种做法,一种是 扩展域(种类并查集),一种是 边带权(带权并查集)。种类并查集貌似应该都比带权并查集简单,所以先讲种类并查集的做法,再讲带权并查集
种类并查集
若 sum[ l ~ r ] 表示 l到r 之间1的个数,sum是一个前缀和数组,那么有 sum [ l ~ r ] = sum[ r ] - sum[ l - 1 ] 。如果有sum[ l ~ r]为奇数个,那么 sum[ r ]和sum[ l - 1 ]肯定奇偶性不同;如果有sum[ l ~ r]为偶数个,那么 sum[ r ]和sum[ l - 1 ]肯定奇偶性相同(这个很简单吧,同奇(偶)-同奇(偶)= =偶,偶-奇= =奇),知道这些之后,我们就可以吧区间[ l ~ r ] 转换为 [ l - 1 ] 和 [ r ] 两个区间,继续往后看
对于一个集合x,我们把它扩展成两个东西,x和x+n,分别表示奇数域和偶数域(不知道为什么这样做的可以去看看我并查集的那篇博客 无耻宣传),那么x表示sum[x]为奇数,x+n表示sum[x]为偶数
因为这道题n的数据范围很大,但是m个操作其实不大,那我们需要对所有数据离散化(离散化教程看另外一篇博客 再次无耻)。对于每个问题 我们设x为l-1的离散化之后的数,y为r离散化之后的数,ans表示当前的回答
①ans=0,表示x和y,x+n和y+n 可以相互推出来,合并
②ans=1,表示x和y+n,x+n和y 可以相互推出来,合并
这样的合并其实可以维护元素之间关系的传递性,即“敌人的敌人就是朋友”这种关系(种类并查集入门)。那么如果x与y在同一集合中,那么奇偶性相同;如果x和y+n在同一集合中,那么奇偶性不同。那么这道题的程序就出来了
#include<bits/stdc++.h>
using namespace std;
struct node {
int l,r,ans;
} ask[40005]; //l,r,ans的意义见上面的文字
int n,m;
int f[40005],a[40005];
int find(int x) {
if(x==f[x]) return x;
return f[x]=find(f[x]);
}
void merge(int x,int y) {
f[find(x)]=find(y);
} //基本操作
int main() {
scanf("%d%d",&n,&m);
int tot=0;
for(register int i=1; i<=m; i++) {
char op[5];
scanf("%d%d",&ask[i].l,&ask[i].r);
cin>>op;
if(op[0]=='o') ask[i].ans=1;
else ask[i].ans=0;
a[++tot]=ask[i].l;
a[++tot]=ask[i].r;
}
sort(a+1,a+1+tot);
n=unique(a+1,a+1+tot)-a-1;
for(register int i=1; i<=2*n; i++) f[i]=i;
for(register int i=1; i<=m; i++) {
ask[i].l=lower_bound(a+1,a+1+n,ask[i].l-1)-a;
ask[i].r=lower_bound(a+1,a+1+n,ask[i].r)-a;
} //以上全部都为离散化
for(register int i=1; i<=m; i++) {
if(ask[i].ans==0) {
if(find(ask[i].l)==find(ask[i].r+n)) {
cout<<i-1;
return 0;
}
merge(ask[i].l,ask[i].r);
merge(ask[i].l+n,ask[i].r+n);
}else{
if(find(ask[i].l)==find(ask[i].r)){
cout<<i-1;
return 0;
}
merge(ask[i].l,ask[i].r+n);
merge(ask[i].l+n,ask[i].r);
}
}
cout<<m;
return 0;
}
带权并查集
带权并查集,真的很麻烦!!!(看这个之前先去了解上面种类并查集的做法,有相同的地方)
用带权并查集,那么我们应该怎么维护这个边权呢?这个边权应该是什么呢?
不难想到,这道题的边权就是 子节点与父节点的奇偶关系。对于边权 d[ x ]表示 x 与 f[ x ] 之间的奇偶关系,0表示相同,1表示不同
那么在路径压缩的时候,怎么维护与根节点之间的奇偶性呢?我们对x到根节点路径上的所有边权进行异或运算,就可以维护这个奇偶性了
若x和y两个节点在一个集合中,对x维护之后,y也维护之后,那么d[x]和d[y]异或之后就是x和y的奇偶关系了,我们画图理解(这辈子都想不清楚图为什么这么小,)
如果要合并x和y两个集合,若p为x的根节点,q为y的根节点,我们把p,q合并,那么x与y的奇偶性应该是 d[ x ] ^ d[ y ] ^ d[ p ],这里的 d[ p ]应该是d[ x ] ^ d[ y ] ^ ans,继续画图理解(貌似清晰一点了)
这样看来,程序也该出来了吧
#include<bits/stdc++.h>
using namespace std;
struct node{
int l,r,ans;
}ask[20005];
int n,m;
int f[20005],d[20005],a[20005];
int find(int x){
if(x==f[x]) return x;
int root=find(f[x]);
d[x]^=d[f[x]];
return f[x]=root; //继续维护啊
}
void merge(int x,int y,int i){
int fx=find(x),fy=find(y);
f[fx]=fy;
d[fx]=d[x]^d[y]^ask[i].ans; //维护啊
}
int main(){
scanf("%d%d",&n,&m);
int tot=0;
for(register int i=1;i<=m;i++){
char op[5];
scanf("%d%d",&ask[i].l,&ask[i].r);
cin>>op;
if(op[0]=='o') ask[i].ans=1;
else ask[i].ans=0;
a[++tot]=ask[i].l;
a[++tot]=ask[i].r;
}
sort(a+1,a+1+tot);
n=unique(a+1,a+1+tot)-a-1; //离散化这里一定要-1哦
for(register int i=1;i<=n;i++) f[i]=i;
for(register int i=1;i<=m;i++){
ask[i].l=lower_bound(a+1,a+1+n,ask[i].l-1)-a;
ask[i].r=lower_bound(a+1,a+1+n,ask[i].r)-a;
}
for(register int i=1;i<=m;i++){
if(find(ask[i].l)==find(ask[i].r)){
if((d[ask[i].l]^d[ask[i].r])!=ask[i].ans){
cout<<i-1;
return 0;
}
}else merge(ask[i].l,ask[i].r,i);
}
cout<<m;
return 0;
}
题解 P5937 【[CEOI1999]Parity Game】的更多相关文章
- [CEOI1999]Parity Game 题解
P5937 [CEOI1999]Parity Game 洛谷P5937 P5937 [CEOI1999]Parity Game 前言: 个人感觉这道题初看想不到并查集啊!(说实话我题都没读懂,第二遍才 ...
- CF1272E. Nearest Opposite Parity 题解 广度优先搜索
题目链接:http://codeforces.com/contest/1272/problem/E 题目大意: 有一个长度为n的数组 \(a\) ,数组坐标从 \(1\) 到 \(n\) . 假设你现 ...
- CF1110A Parity 题解
Content 求下面式子的奇偶性,其中 \(a_i,k,b\) 会在输入中给定. \[\sum\limits_{i=1}^k a_i\cdot b^{k-i} \] 数据范围:\(2\leqslan ...
- Codeforces 549C. The Game Of Parity[博弈论]
C. The Game Of Parity time limit per test 1 second memory limit per test 256 megabytes input standar ...
- Codeforces Round #180 (Div. 2) C. Parity Game 数学
C. Parity Game 题目连接: http://www.codeforces.com/contest/298/problem/C Description You are fishing wit ...
- poj1733 Parity Game(扩展域并查集)
描述 Now and then you play the following game with your friend. Your friend writes down a sequence con ...
- POJ1733 Parity game 【扩展域并查集】*
POJ1733 Parity game Description Now and then you play the following game with your friend. Your frie ...
- 【POJ1733】Parity game
[POJ1733]Parity game 题面 vjudge 题解 比较简单的分类并查集 将一个查询操作看作前缀和\(s_r-s_{l-1}\)的奇偶性 将每个点拆成一奇一偶然后分别连边即可 如果一个 ...
- Codeforces Global Round 1 (A-E题解)
Codeforces Global Round 1 题目链接:https://codeforces.com/contest/1110 A. Parity 题意: 给出{ak},b,k,判断a1*b^( ...
随机推荐
- Java实现 LeetCode 665 非递减数列(暴力)
665. 非递减数列 给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列. 我们是这样定义一个非递减数列的: 对于数组中所有的 i (1 < ...
- Java实现分割矩形
给定平面内平行于坐标轴的一个矩形,从矩形内选 择一些点,从这些点向右和向上各射出一条射线, 请问:这些射线将矩形分成了多少份. 数据格式: 输入的第一行包含两个整数x, y,表示矩形是由(0, 0), ...
- java实现漏掉的账目明细
某财务部门结账时发现总金额不对头.很可能是从明细上漏掉了某1笔或几笔.如果已知明细账目清单,能通过编程找到漏掉的是哪1笔或几笔吗? 如果有多种可能,则输出所有可能的情况. 我们规定:用户输入的第一行是 ...
- java实现第六届蓝桥杯三角形面积
三角形面积 题目描述 如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何多余内容或说明性文字. 28 简单的数学平面几何问题: 大正方形面 ...
- java代码(15) ---java8 Function 、Consumer 、Supplier
Java8 Function.Consumer.Supplier 有关JDK8新特性之前还有三篇博客: 1,java代码(1)---Java8 Lambda 2,java代码(2)---Java8 S ...
- TZOJ 公交车
描述 公交车在一条笔直的道路(道路宽度忽略,设为X轴)上行驶,按顺序路上有若干个站点(X坐标值),crq的家也在道路旁某个位置h(X坐标值),现在crq想知道哪个站点下车离家最近. 输入 输入数据的第 ...
- (十一)DVWA全等级SQL Injection(Blind)盲注--手工测试过程解析
一.DVWA-SQL Injection(Blind)测试分析 SQL盲注 VS 普通SQL注入: 普通SQL注入 SQL盲注 1.执行SQL注入攻击时,服务器会响应来自数据库服务器的错误信息,信息提 ...
- 如何在交互式环境中执行Python程序
相信接触过Python的小伙伴们都知道运行Python脚本程序的方式有多种,目前主要的方式有:交互式环境运行.命令行窗口运行.开发工具上运行等,其中在不同的操作平台上还互不相同.今天,小编讲些Pyth ...
- chrome浏览器版本与驱动不匹配问题的解决办法
1.浏览器与驱动如何匹配才不会报错 使用selenium模块的webdriver打开谷歌浏览器时常遇到这样的错误提示: selenium.common.exceptions.WebDriverExce ...
- JPA 中 find() 和 getReference() 的区别
在查询的时候有两个方法:find()和getReference(),这两个方法的参数以及调用方式都相同.那么这两个方法有什么不一样的呢? find()称为 立即加载,顾名思义就是在调用的时候立即执行查 ...