1594: [Usaco2008 Jan]猜数游戏

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 626  Solved: 260
[Submit][Status][Discuss]

Description

为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力。 游戏开始前,一
头指定的奶牛会在牛棚后面摆N(1 <= N<= 1,000,000)堆干草,每堆有若干捆,并且没有哪两堆中的草一样多。所
有草堆排成一条直线,从左到右依次按1..N编号,每堆中草的捆数在1..1,000,000,000之间。 然后,游戏开始。
另一头参与游戏的奶牛会问那头摆干草的奶牛 Q(1 <= Q <= 25,000)个问题,问题的格式如下: 编号为Ql..Qh(1 
<= Ql <= Qh <= N)的草堆中,最小的那堆里有多少捆草? 对于每个问题,摆干草的奶牛回答一个数字A,但或许
是不想让提问的奶牛那么容易地得到答案,又或许是她自己可能记错每堆中干草的捆数,总之,她的回答不保证是
正确的。 请你帮助提问的奶牛判断一下,摆干草的奶牛的回答是否有自相矛盾之处。

Input

* 第1行: 2个用空格隔开的整数:N 和 Q
* 第2..Q+1行: 每行为3个用空格隔开的整数Ql、Qh、A,描述了一个问题以及它 对应的回答

Output

* 第1行: 如果摆干草的奶牛有可能完全正确地回答了这些问题
(也就是说,能 找到一种使得所有回答都合理的摆放干草的方法),输出0,
否则输出 1个1..Q中的数,表示这个问题的答案与它之前的那些回答有冲突之处
注意:如果有冲突出现输出一个数m,使得前M-1个命题不冲突。

Sample Input

20 4
1 10 7
5 19 7
3 12 8
11 15 12
输入说明:
编号为1..10的草堆中,最小的那堆里有7捆草,编号为5..19的草堆中同样如此;编号为3..12的草堆中最小的堆里
是8捆草,11..15堆中的最小的堆里是12捆。

Sample Output

3
输出说明:
对于第3个问题“3 12”的回答“8”与前面两个回答冲突。因为每堆中草的捆数唯一,从前两个回答中我们能推断
出,编号为5..10的干草堆中最小的那堆里有7捆干草。很显然,第3个问题的回答与这个推断冲突。

题解

矛盾只有两种情况:

一.先前确定了x在区间(l,r),但是现在发现x在区间(l1,r1),并且两个区间不相交。

二.一个区间的最小值是x,这个区间中有一个子区间的最小值比x更小。

然后我们先考虑第一种情况

先对权值离散化,然后对于每一个权值维护它的交集,如果发现不相交,记录当前回答的位置。

这个位置前的所有回答都不会出现第一种矛盾,且答案一定小于等于当前位置。

所以我们把问题转化为问前几个回答最早在哪里出现第二种矛盾。

我们按权值为第一关键字编号为第二关键字给回答排序。

对于每一个权值像刚才一样求交集。

当交集被大于当前权值的并集包含时,说明出现矛盾。

此时的答案是max(组成当前权值交集的回答的最大编号,交集位置上大于当前权值的区间的编号的最大值(这个用线段树维护));

然后多个区间的交集我们在线段树上记录这多个区间对应的回答的编号的最小值。

 #include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
const int N=;
int mal[N],mar[N],b[N],q,m,n,last,ans;
struct query{
int l,r,w,id;
}c[N];
struct tree{
int l,r,sum,lazy,mn;
}tr[];
bool cmp(query a,query b){
if(a.w==b.w)return a.id<b.id;
return a.w>b.w;
}
void update(int now){
tr[now].sum=tr[now*].sum+tr[now*+].sum;
tr[now].mn=max(tr[now*].mn,tr[now*+].mn);
}
void build(int l,int r,int now){
tr[now].l=l;tr[now].r=r;
tr[now].lazy=;
if(l==r){
tr[now].mn=;
return;
}
int mid=(l+r)>>;
build(l,mid,now*);
build(mid+,r,now*+);
update(now);
}
void pushdown(int now){
if(tr[now].lazy==)return;
tr[now*].sum=tr[now*].r-tr[now*].l+;
tr[now*].mn=min(tr[now*].mn,tr[now].lazy);
tr[now*].lazy=min(tr[now*].lazy,tr[now].lazy);
tr[now*+].sum=tr[now*+].r-tr[now*+].l+;
tr[now*+].mn=min(tr[now*+].mn,tr[now].lazy);
tr[now*+].lazy=min(tr[now*+].lazy,tr[now].lazy);
tr[now].lazy=;
}
void change(int l,int r,int c,int now){
pushdown(now);
if(tr[now].l==l&&tr[now].r==r){
tr[now].sum=tr[now].r-tr[now].l+;
tr[now].lazy=c;
tr[now].mn=min(tr[now].mn,c);
return ;
}
int mid=(tr[now].l+tr[now].r)>>;
if(l>mid)change(l,r,c,now*+);
else if(r<=mid)change(l,r,c,now*);
else{
change(l,mid,c,now*);
change(mid+,r,c,now*+);
}
update(now);
}
int getsum(int l,int r,int now){
pushdown(now);
if(tr[now].l==l&&tr[now].r==r){
return tr[now].sum;
}
int mid=(tr[now].l+tr[now].r)>>;
if(l>mid)return getsum(l,r,now*+);
else if(r<=mid)return getsum(l,r,now*);
else return getsum(l,mid,now*)+getsum(mid+,r,now*+);
}
int getmax(int l,int r,int now){
pushdown(now);
if(tr[now].l==l&&tr[now].r==r){
return tr[now].mn;
}
int mid=(tr[now].l+tr[now].r)>>;
if(l>mid)return getmax(l,r,now*+);
else if(r<=mid)return getmax(l,r,now*);
else return max(getmax(l,mid,now*),getmax(mid+,r,now*+));
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
scanf("%d%d%d",&c[i].l,&c[i].r,&c[i].w);
b[i]=c[i].w;
c[i].id=i;
}
sort(b+,b++m);
int tot=unique(b+,b++m)-b-;
for(int i=;i<=m;i++){
c[i].w=lower_bound(b+,b++tot,c[i].w)-b;
}
bool flag=false;
for(int i=;i<=m;i++){
if(mal[c[i].w]==&&mar[c[i].w]==){
mal[c[i].w]=c[i].l;
mar[c[i].w]=c[i].r;
}
else{
if(c[i].l>mar[c[i].w]||c[i].r<mal[c[i].w]){
q=i-;
flag=true;
break;
}
else{
if(mal[c[i].w]<=c[i].l&&c[i].r<=mar[c[i].w]){
mal[c[i].w]=c[i].l;
mar[c[i].w]=c[i].r;
}
else{
if(mal[c[i].w]<=c[i].l&&c[i].l<=mar[c[i].w]){
mal[c[i].w]=c[i].l;
}
else if(mal[c[i].w]<=c[i].r&&c[i].r<=mar[c[i].w]){
mar[c[i].w]=c[i].r;
}
}
}
}
}
build(,n,);
if(flag==false)q=m;
sort(c+,c++q,cmp);
last=;
for(int i=;i<=q;i++){
mal[c[i].w]=mar[c[i].w]=;
}
ans=min(m,q+);
for(int i=;i<=q;i++){
if(c[i].w!=c[i-].w){
for(int j=last;j<=i-;j++){
change(c[j].l,c[j].r,c[j].id,);
}
last=i;
}
if(mal[c[i].w]==&&mar[c[i].w]==){
mal[c[i].w]=c[i].l;
mar[c[i].w]=c[i].r;
}
else{
if(mal[c[i].w]<=c[i].l&&c[i].r<=mar[c[i].w]){
mal[c[i].w]=c[i].l;
mar[c[i].w]=c[i].r;
}
else{
if(mal[c[i].w]<=c[i].l&&c[i].l<=mar[c[i].w]){
mal[c[i].w]=c[i].l;
}
else if(mal[c[i].w]<=c[i].r&&c[i].r<=mar[c[i].w]){
mar[c[i].w]=c[i].r;
}
}
}
if(mar[c[i].w]-mal[c[i].w]+==getsum(mal[c[i].w],mar[c[i].w],)){
ans=min(ans,max(c[i].id,getmax(mal[c[i].w],mar[c[i].w],)));
flag=true;
}
}
if(flag==false)printf("");
else printf("%d",ans);
return ;
}

BZOJ 1594 [Usaco2008 Jan]猜数游戏(线段数)的更多相关文章

  1. bzoj 1594: [Usaco2008 Jan]猜数游戏——二分+线段树

    Description 为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力. 游戏开始前,一头指定的奶牛会在牛棚后面摆N(1 <= N<= 1,000,00 ...

  2. BZOJ 1594: [Usaco2008 Jan]猜数游戏 线段树 + 思维 + 二分

    Code: #include<bits/stdc++.h> #define maxn 3000000 using namespace std; void setIO(string s) { ...

  3. bzoj 1594: [Usaco2008 Jan]猜数游戏【二分+线段树】

    写错一个符号多调一小时系列-- 二分答案,然后判断这个二分区间是否合法: 先按值从大到小排序,然后对于值相同的一些区间,如果没有交集则不合法:否则把并集在线段树上打上标记,然后值小于这个值的区间们,如 ...

  4. 【BZOJ 1594】 [Usaco2008 Jan]猜数游戏 (二分+并查集)

    1594: [Usaco2008 Jan]猜数游戏 Description 为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力. 游戏开始前,一头指定的奶牛会在牛棚后面 ...

  5. 【BZOJ1594】[Usaco2008 Jan]猜数游戏 二分答案+并查集

    [BZOJ1594][Usaco2008 Jan]猜数游戏 Description 为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力. 游戏开始前,一头指定的奶牛会在 ...

  6. Bzoj 1612: [Usaco2008 Jan]Cow Contest奶牛的比赛 传递闭包,bitset

    1612: [Usaco2008 Jan]Cow Contest奶牛的比赛 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 891  Solved: 590 ...

  7. BZOJ 1612: [Usaco2008 Jan]Cow Contest奶牛的比赛( floyd )

    对于第 i 头牛 , 假如排名比它高和低的数位 n - 1 , 那么他的 rank 便可以确定 . floyd -------------------------------------------- ...

  8. [bzoj1594] [Usaco2008 Jan]猜数游戏

    二分答案(二分没冲突的前Q-1个问题),用并查集判定(用法同bzoj 1576) 假设一个询问区间[l,r],最小干草堆数目是A,我们可以得出[l,r]上的干草堆数目都>=A. 二分出mid后, ...

  9. [BZOJ1594] [Usaco2008 Jan]猜数游戏(二分 + 并查集)

    传送门 题中重要信息,每堆草的数量都不一样. 可以思考一下,什么情况下才会出现矛盾. 1.如果两个区间的最小值一样,但是这两个区间没有交集,那么就出现矛盾. 2.如果两个区间的最小值一样,并且这两个区 ...

随机推荐

  1. Unity坐标系 左手坐标系 图

    x轴:从左指向右 y轴:从下指向上 z轴:指向屏幕里的是左手坐标系,指向屏幕外的是右手坐标系 记忆小技巧:都是X轴朝右,Y轴向上,跟平时画坐标一模一样,区别只是Z的朝向.你用手试一下就知道了,当大拇指 ...

  2. ZBrush软件中的笔触类型

    在ZBrush® 中我们通过各种笔触类型,确定在使用ZBrush®画笔进行绘制时画笔的变化方式及状态.使用多种画笔绘制根据选择不同的笔触组合绘制,能够得到繁多变化丰富的制作效果. 选择笔触的类型 点击 ...

  3. Eclipse中合并GIT分支

    合并GIT分支: 1.  切换到主分支: 2.  右击项目——Team——Merge…: 3.  在弹出的Merge框中选择要合并的分支——Merge: 4.  合并后如果出现冲突,右击项目——Tea ...

  4. node——try-catch与异步操作

    //try-catch,用于捕获异常 //try-catch在node中只能捕获同步的异常,不能捕获异步异常 var fs=require('fs'); /*fs.writeFile('./abc.t ...

  5. 02操控奴隶——掌握它的语言“Python”

    一 编程常识 1编程语言的发展史 程序员是计算机的主人,主人与奴隶沟通的介质是编程语言,编程语言从诞生到现在它经历了那几个阶段呢? 2 语言的特性: 3 初期的编程语言更多的是站在计算机的角度去设计编 ...

  6. 用Arcade表达式添加标签

    Arcade表达式是轻量级的脚本语言,我们可以通过全局变量$feature获取要素属性.比如说,要为城市添加标签,利用CITY_NAME列,我们可以编写语句:$feature.CITY_NAME.Ar ...

  7. tp volist需要便利两个数组时的处理办法

    你需要便利两个数组,并且需要使用key 和value的试的时候,volist是否先得有些捉鸡? 我们可以便利其中一个数组,而另一个利用数组的指针来操作 next($arr) 将数组指针下移 key($ ...

  8. dubbo 部分 配置的关系-dubbo github 官方案例

    1.dubbo 有一个 dubbo.properties 作为默认配置 默认配置可以在不添加新的配置的前提下使用dubbo dubbo.properties 的内容(来自 https://github ...

  9. ASP.NET-入门

    MVC5特点 1.One ASP.NET统一平台  2.Bootstrap 免费CSS,响应式页面 3.路由标记属性:简单.控制器.操作.前缀.参数.URL 4.ASP.NET web API 2 : ...

  10. php获取当前url地址的方法小结

    js 获取: top.location.href //顶级窗口的地址 this.location.href //当前窗口的地址 php获取当前url地址: #测试网址: http://localhos ...