【BZOJ 3387】 线段树= =
57 跨栏训练
为了让奶牛参与运动,约翰建造了 K 个栅栏。每条栅栏可以看做是二维平面上的一条线段,它
们都平行于 X 轴。第 i 条栅栏所覆盖的 X 轴坐标的区间为 [ Ai,Bi ], Y 轴高度就是 i。一开始,奶牛
在坐标 (S,K + 1) 处,它们的家在原点处,所以要想要回家就必须“跨”一些栅栏。
但奶牛们是跨不过栅栏的,它们只能绕过栅栏。在二维平面上,它们只能沿水平和垂直方向移动,
如果前进的道路上出现栅栏,它们就不能前进,必须沿水平方向移动到没有栅栏的地方再前进。奶牛
们希望走的路越短越好,由于在垂直方向上的路程是确定的,你只需要帮它们求出在水平方向的最短
路程就可以了。
输入格式
• 第一行:两个整数 K 和 S, 1 ≤ K ≤ 50000, − 105 ≤ S ≤ 105
• 第二行到第 N + 1 行:第 i + 1 行有两个整数 Ai 和 Bi, − 105 ≤ Ai ≤ Bi ≤ 105
输出格式
• 单个整数:表示奶牛从起点到终点在水平方向移动的最短总距离
样例输入
4 0
-2 1
-1 2
-3 0
-2 1
样例输出
4
解释
第四个栅栏是最先遇到的,向右移一格绕过
它。为了绕过第二个栅栏,再向右移一格,最后
为了回到原点向左移两格
【分析】
就是,差不多,像是个模拟的东西,如果没有东西挡着你,就不用走了(如果要走,等一下有东西挡着你再走)、
如果有东西挡着你,就走到栅栏左边或者栅栏右边(不用多走,要是需要多走,等一下再走)
但是询问区间的话每个点到栅栏左端点需要加的距离是不一样的,所以我们维护的时候不是他走的距离,而是他走的距离在加上他走到图的最左边的距离。
右边也一样。
就是一个区间修改成INF的操作 以及单点修改 还有区间查询。
代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 200010
#define Maxk 50010
#define INF 0xfffffff int a[Maxk],b[Maxk]; struct node
{
int l,r,lc,rc,a1,a2;
bool lazy;
}t[Maxn*];int len; int mymin(int x,int y) {return x<y?x:y;}
int mymax(int x,int y) {return x>y?x:y;}
int mn=INF,mx=; int build(int l,int r)
{
int x=++len;
t[x].l=l;t[x].r=r;t[x].a1=t[x].a2=INF;
t[x].lazy=;
if(l!=r)
{
int mid=(l+r)>>;
t[x].lc=build(l,mid);
t[x].rc=build(mid+,r);
}
return x;
} void upd(int x)
{
if(t[x].lazy==) return;
if(t[x].l!=t[x].r)
{
int lc=t[x].lc,rc=t[x].rc;
t[lc].lazy=;t[rc].lazy=;
}
t[x].a1=t[x].a2=INF;
t[x].lazy=;
} void change(int x,int l,int r)
{
if(l>r) return;
upd(x);
if(t[x].l==l&&t[x].r==r)
{
t[x].lazy=;
return;
}
int mid=(t[x].l+t[x].r)>>;
if(r<=mid) change(t[x].lc,l,r);
else if(l>mid) change(t[x].rc,l,r);
else
{
change(t[x].lc,l,mid);
change(t[x].rc,mid+,r);
}
int lc=t[x].lc,rc=t[x].rc;
upd(lc);upd(rc);
t[x].a1=mymin(t[lc].a1,t[rc].a1);
t[x].a2=mymin(t[lc].a2,t[rc].a2);
} void change2(int x,int y,int z)
{
upd(x);
if(t[x].l==t[x].r)
{
t[x].a1=mymin(t[x].a1,z+y);
t[x].a2=mymin(t[x].a2,z+mx-y);
return;
}
int mid=(t[x].l+t[x].r)>>;
if(y<=mid) change2(t[x].lc,y,z);
else change2(t[x].rc,y,z);
int lc=t[x].lc,rc=t[x].rc;
upd(lc);upd(rc);
t[x].a1=mymin(t[lc].a1,t[rc].a1);
t[x].a2=mymin(t[lc].a2,t[rc].a2);
} int query(int x,int l,int r,bool p)
{
if(l>r) return INF;
upd(x);
if(t[x].l==l&&t[x].r==r)
{
if(!p) return t[x].a1;
else return t[x].a2;
}
int mid=(t[x].l+t[x].r)>>;
if(r<=mid) return query(t[x].lc,l,r,p);
else if(l>mid) return query(t[x].rc,l,r,p);
else return mymin(query(t[x].lc,l,mid,p),query(t[x].rc,mid+,r,p));
} int main()
{
int k,s;
scanf("%d%d",&k,&s);
for(int i=;i<=k;i++)
{
scanf("%d%d",&a[i],&b[i]);
mn=mymin(mn,a[i]);
mx=mymax(mx,b[i]);
}
mn=-mn+;
for(int i=;i<=k;i++) a[i]+=mn,b[i]+=mn;
mx+=mn;
len=;
build(,mx);
change2(,+mn,);
for(int i=;i<=k;i++)
{
int n1=query(,a[i]+,b[i]-,),n2=query(,a[i]+,b[i]-,);
if(n1!=INF) change2(,a[i],n1-a[i]);
if(n2!=INF) change2(,b[i],n2-(mx-b[i]) );
change(,a[i]+,b[i]-); }
s+=mn;
int ans=mymin(query(,,s,)-(mx-s),query(,s,mx,)-s);
printf("%d\n",ans);
return ;
}
[BZOJ 3387]
2016-10-31 15:17:12
【BZOJ 3387】 线段树= =的更多相关文章
- BZOJ 1798 (线段树||分块)的标记合并
我原来准备做方差的.. 结果发现不会维护两个标记.. 就是操作变成一个 a*x+b ,每次维护a , b 即可 加的时候a=1 ,b=v 乘的时候a=v ,b=0 #include <cstdi ...
- bzoj 3999 线段树区间提取 有序链剖
看错题目了,想成每个城市都可以买一个东西,然后在后面的某个城市卖掉,问最大收益.这个可以类似维护上升序列的方法在O(nlog^3n)的时间复杂度内搞定 这道题用到的一些方法: 1. 可以将有关的线段提 ...
- bzoj 3211 线段树
开方操作最多进行5次就可以把出现的任何数变成1. 所以用线段树暴力修改,以后修改时只需看一下是否当前区间都是0或1,如果是那么就直接返回. /***************************** ...
- bzoj 1018 线段树维护连通性
本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护. 对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边 ...
- bzoj 3212 线段树
裸的线段树 /************************************************************** Problem: User: BLADEVIL Langua ...
- bzoj 2120 线段树套平衡树
先吐下槽,改了快一个小时,最后发现是SBT的delete写错了,顿时就有想死的心..... 首先对于这道题,我们应该先做一下他的小问题,bzoj1878,虽然和这道题几乎一点关系没有, 但是能给我们一 ...
- bzoj 1901 线段树套平衡树+二分答案查询
我们就建一颗线段树,线段树的每一个节点都是一颗平衡树,对于每个询问来说,我们就二分答案, 查询每个二分到的mid在这个区间里的rank,然后就行了 /************************* ...
- BZOJ 1012 线段树||单调队列
非常裸的线段树 || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件 ...
- BZOJ 3681 线段树合并+网络流
思路: 暴力建图有n*m条边 考虑怎么优化 (那就只能加个线段树了呗) 然后我就不会写了..... 抄了一波题解 //By SiriusRen #include <bits/stdc++.h&g ...
- BZOJ 4756 线段树合并(线段树)
思路: 1.最裸的线段树合并 2. 我们可以观察到子树求一个东西 那我们直接DFS序好了 入队的时候统计一下有多少比他大的 出的时候统计一下 减一下 搞定~ 线段树合并代码: //By SiriusR ...
随机推荐
- 一个项目覆盖CS所有课程的可行性探究
我们先看计算机科学有哪些子领域. 学术领域有: 计算理论 信息和编码理论 算法和数据结构 形式化方法 程序设计语言 实践领域有: 计算机体系结构 并行计算和分布式系统 实时系统和嵌入式系统 操作系统 ...
- C++学习(四)
一.拷贝构造函数和拷贝赋值运算符1.拷贝构造:用一个已有的对象,构造和它同类型的副本对象——克隆.2.形如class X { X (const X& that) { ... }};的构造函数 ...
- 谨以此错误警醒自己---java.lang.ClassNotFoundException:
今天在做一个小型的实例,用了面向接口编程,采用了工厂来获取数据源和实例,在从配置文件读取实例时,报了个错误如下图: 于是一个一个的类去找错误,最后也没找到,以为工厂代码出错了,看了好几次也没看出来错误 ...
- 20151215jquery学习笔记--jqueryUI --dialog(对话框)
对话框(dialog),是 jQuery UI 非常重要的一个功能.它彻底的代替了 JavaScript 的 alert().prompt()等方法,也避免了新窗口或页面的繁杂冗余 一.开启多个 di ...
- 学习笔记_Java get和post区别(转载_GET一般用于获取/查询资源信息,而POST一般用于更新资源信息)
转载自:[hyddd(http://www.cnblogs.com/hyddd/)] 总结一下, Get是向服务器发索取数据的一种请求 而Post是向服务器提交数据的一种请求,在F ...
- [linux] 系统管理常用命令
1.查看某个软件是否安装: rpm -qa|grep software_name 2.top命令,显示系统的动态视图,q退出 3.ps aux|grep process_name 显示正在运行的进程 ...
- IOS开发中针对UIImageView的几种常用手势
// // ViewController.m // 05-手势 // // Created by wanghy on 15/9/21. // Copyright (c) 2015年 wangh ...
- 导入外部jar包的方法
注:使用的编译平台为eclipse <算法>一书中需要引入外部jar包(algs4.jar),因此特地去学了下导入外部jar包的方法.步骤如下: 1.先将algs4.jar拷到j如下路径: ...
- RD / RMDIR Command
Quote from: http://ss64.com/nt/rd.html RD Delete folder(s) Syntax RD pathname RD /S pathname RD /S / ...
- 使用SqlBulkCopy批量插入多条数据进入表中
由于工作中项目需求结算一次生成一批相同批次号的数据插入一个表中,然后再通过另一页面展示出来,所以需要用到一次性插入一批数据,所以就采用了SqlBulkCopy插入一批数据 1 public stati ...