原题:

题目描述

   huyichen和xuzhenyi在玩一个游戏:他写一个由0和1组成的序列。 huyichen选其中的一段(比如第3位到第5位),问他这段里面有奇数个1 还是偶数个1。xuzhenyi回答你的问题,然后huyichen继续问。 xuzhenyi有可能在撒谎。huyichen要检查xuzhenyi的答案,指出在xuzhenyi的第几个回答一定有问题。 有问题的意思就是存在一个01序列满足这个回答前的所有回答,而且不存在序列 满足这个回答前的所有回答及这个回答。

输入格式

第1行一个整数,是这个01序列的长度(≤1000000000)(≤1000000000) 第2行一个整数,是问题和答案的个数(≤5000)(≤5000)。 第3行开始是问题和答案, 每行先有两个整数,表示你询问的段的开始位置和结束位置。 然后是xuzhenyi的回答。odd表示有奇数个1,even表示有偶数个

输出格式

输出一行,一个数X,表示存在一个01序列满足第1到第X个回答, 但是不存在序列满足第1到第X+1个回答。如果所有回答都没问题,你就输出 所有回答的个数。


很明显,这道题是并查集(不要问我怎么看出来的)。

由于数据太大,需要离散化。

所谓离散化,就是把较大的一组数进行排序,然后对他们根据大小重新赋值,当数的大小不对数据本身有影响,只有大小对其有影响时,可以使用离散化。

离散化的标准姿势见 点这里

然而蒟蒻并不会标准姿势,说说自己的方法:

以本题为例,把所有的数据都存在nd结构体中

void init()
{
for(int i = ;i<=m;i++)
{
int x,y;
scanf("%d%d%s",&x,&y,c);
nd[i].p = x;//数组开三倍,p表示临时变量。一倍存左端点。
nd[i+m].p = y;//二倍存右端点。
nd[i].num = i;//每一倍都要给他们打上编号,一会排序时后会乱。
nd[i+m].num = i;if(c[]=='e')
{
nd[i+m+m].odd = ;//三倍存奇偶
}else
{
nd[i+m+m].odd = ;
}
}
}

读进来之后进行离散化。

void discretization()
{
for(int i = ;i<=*m;i++)
{
if(nd[nd[i].num].l==-)
{
nd[nd[i].num].l = cnt-;
}else
{
nd[nd[i].num].r = cnt;
}
if(nd[i+].p!=nd[i].p)
{
cnt++; //去重,不一样的时候再+1
}
}
for(int i = ;i<=m;i++)
{
nd[i].odd = nd[i+m+m].odd;从三倍搬回原数组
}
}

这样就离散完了。

接下来就是带权并查集的操作。

在合并和路径压缩的时候处理。

思路就是将一个区间右面的点认左面的点为父亲,两端区间合并的时候,根据奇偶性判断,0表示偶数,1表示奇数(有点懒,具体0或1见代码)。

int find(int x)
{
if(f[x]==x)
{
return f[x];
}
int fx = find(f[x]);
g[x] = (g[f[x]]+g[x])%;
return f[x] = fx;
}

最后上总代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 105550
using namespace std;
char c[];
ll n;
int m;
int cnt = ;
struct node
{
int l;
int r;
int num;
int odd;
int p;
}nd[N+N+N];
int f[N];
int g[N];
int cmp(node a,node b)
{
return a.p < b.p;
}
void init()
{
for(int i = ;i<=m;i++)
{
int x,y;
scanf("%d%d%s",&x,&y,c);
nd[i].p = x;
nd[i+m].p = y;
nd[i].num = i;
nd[i+m].num = i;
nd[i].l = -;
nd[i+m].l = -;
if(c[]=='e')
{
nd[i+m+m].odd = ;
}else
{
nd[i+m+m].odd = ;
}
}
}
void discretization()
{
for(int i = ;i<=*m;i++)
{
if(nd[nd[i].num].l==-)
{
nd[nd[i].num].l = cnt-;
}else
{
nd[nd[i].num].r = cnt;
}
if(nd[i+].p!=nd[i].p)
{
cnt++;
}
}
for(int i = ;i<=m;i++)
{
nd[i].odd = nd[i+m+m].odd;
}
}
int find(int x)
{
if(f[x]==x)
{
return f[x];
}
int fx = find(f[x]);
g[x] = (g[f[x]]+g[x])%;
return f[x] = fx;
}
int ans;
bool flag;
void uion(int x,int y,int i)
{
int fx = find(x);
int fy = find(y);
if(fx==fy)
{
if((nd[i].odd==&&g[x]==g[y])||(nd[i].odd==&&g[x]!=g[y]))
{
ans = i-;
flag = ;
return ;
}
find(y);
find(x);
}else
{
f[fy] = fx;
g[fy] = (g[x]+g[y]+nd[i].odd)%;
find(x);
find(y);
}
}
void solve()
{
for(int i = ;i<=cnt;i++)
{
f[i] = i;
}
for(int i = ;i<=m;i++)
{
int l = nd[i].l;
int r = nd[i].r;
uion(l,r,i);
if(flag==)
{
printf("%d\n",ans);
return ;
}
}
printf("%d\n",m);
}
int main()
{
scanf("%lld",&n);
scanf("%d",&m);
init();
sort(nd+,nd++m+m,cmp);
discretization();
solve();
return ;
}

小胖的奇偶(Viojs1112)题解的更多相关文章

  1. [vijos P1112] 小胖的奇偶

    第一次看到这题怎么也不会想到是并查集题目…星期五第一次看到这题,到今天做出来,实在是废了好多功夫.看了很多人的解题都有same和diff数组,我也写了,后来发现不对啊两个数组的话find函数怎么写呢? ...

  2. Vijos 小胖的奇偶

    第一遍做 #include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> ...

  3. 【带权并查集】【离散化】vijos P1112 小胖的奇偶

    每个区间拆成r和l-1两个端点,若之内有偶数个1,则这两个端点对应的前缀的奇偶性必须相同,否则必须相反. 于是可以用带权并查集维护,每个结点储存其与其父节点的奇偶性是否相同,并且在路径压缩以及Unio ...

  4. VijosP1112:小胖的奇偶

    描述 huyichen和xuzhenyi在玩一个游戏:他写一个由0和1组成的序列. huyichen选其中的一段(比如第3位到第5位),问他这段里面有奇数个1还是偶数个1.xuzhenyi回答你的问题 ...

  5. BZOJ 3714: [PA2014]Kuglarz

    Description 魔术师的桌子上有n个杯子排成一行,编号为1,2,-,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品.花费c_ij元,魔术师就会告诉你杯子i,i+ ...

  6. 【并查集模板】 【洛谷P2978】 【USACO10JAN】下午茶时间

    P2978 [USACO10JAN]下午茶时间Tea Time 题目描述 N (1 <= N <= 1000) cows, conveniently numbered 1..N all a ...

  7. Tempter of the Bone(dfs+奇偶剪枝)题解

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  8. 力扣(LeetCode)按奇偶排序数组II 个人题解

    给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数. 对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数:当 A[i] 为偶数时, i 也是偶数. 你可以返回任何满足上述条件的数组 ...

  9. 小胖守皇宫(VIJOS P1144 )题解

    题目描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每 ...

随机推荐

  1. Android 8.0的平台上,应用不能对大部分的广播进行静态注册

    引言在Android 8.0的平台上,应用不能对大部分的广播进行静态注册,也就是说,不能在AndroidManifest文件对有些广播进行静态注册,这里必须强调是有些广播,因为有些广播还是能够注册的. ...

  2. 重温拉格朗日乘子法和KKT条件

    在求取有约束条件的优化问题时,拉格朗日乘子法(Lagrange Multiplier) 和KKT条件是非常重要的两个求取方法,对于等式约束的优化问题,可以应用拉格朗日乘子法去求取最优值:如果含有不等式 ...

  3. 对 GAN 的 value function 的理解

    上式分为两个步骤: 第一步:调整discriminative model D的权重,使得V中两项取得最大值 第二步:调整generative model G的权重,使得V中第二项取得最小值 首先,分析 ...

  4. 网络编程之网络架构及其演变过程、互联网与互联网的组成、OSI七层协议、socket抽象层

    目录 网络架构及其演变过程 单机架构 CS架构 BS架构 BS架构和CS架构的区别 C/S架构的优缺点: B/S架构的优缺点: 互联网与互联网的组成 互联网的组成(教科书版) 互联网的组成(科普版) ...

  5. Win10 资源管理器窗口无边框的问题

    将“在窗口下显示阴影”关闭,再重新打开即可. 等了这么久,才敢在工作环境使用Win10,没想到还是这么多bug和不方便之处:输入法.托盘区.蓝屏...

  6. Vue学习之品牌案例部分代码小结(二)

    品牌案例的增删查和其他部分效果: <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  7. html5直接调用手机相机照相/录像

    现在的h5功能越来越强大.之前做项目时上传功能input type=file时,在IOS下居然可以直接照相...但是在安卓上是不能.后面研究 了下,其实安卓下也可以的. 就是在input上加上capt ...

  8. Nexus6p手机root和安装xposed

    进行root前需要两个前提条件 解锁OEM 进入开发者选项:设置-〉关于-〉一直点版本号会出现,usb调试打开 手机连接pc命令行输入: adb reboot bootloader 进入bootloa ...

  9. idea 把 springboot 项目打包成 jar

    在maven项目中,查看是否有maven的插件,无则添加配置maven插件: <build> <plugins> <plugin> <groupId>o ...

  10. Golang: 读取文件并统计内容

    上次我们从命令行接收用户输入,并统计了每次输入内容出现的次数,今天对程序加以改造,使其能够读取文件内容,并统计每行文本出现的次数. 首先,我们把接收输入的逻辑封装成一个函数: // scan.go p ...