【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 ...
随机推荐
- mysql sqlmap 注入尝试
假设注入点为 http://www.abc.com/news.php?id=12 //探测数据库信息 sqlmap -u http://www.abc.com/news.php?id=12 –dbs ...
- JavaScript平常会跳的坑系列(一)
function Foo() { //定义foo函数 getName = function () { console.log('1');}; console.log(this); return thi ...
- 关于微软企业库中依赖注入容器Unity两种生成对象的实现u
http://www.byywee.com/page/M0/S261/261037.html
- 插入排序算法--直接插入算法,折半排序算法,希尔排序算法(C#实现)
插入排序算法主要分为:直接插入算法,折半排序算法(二分插入算法),希尔排序算法,后两种是直接插入算法的改良.因此直接插入算法是基础,这里先进行直接插入算法的分析与编码. 直接插入算法的排序思想:假设有 ...
- SQL Server调优系列基础篇 - 并行运算总结(一)
前言 上三篇文章我们介绍了查看查询计划的方式,以及一些常用的连接运算符.联合运算符的优化技巧. 本篇我们分析SQL Server的并行运算,作为多核计算机盛行的今天,SQL Server也会适时调整自 ...
- C++ -windows与unix路径分隔符
文件路径中通常使用正斜杠和反斜杠 在Windows中 C++中“\\”是一种转义字符,他表示一个‘\’,就像\n表示回车一样.所以C++中的路径名: D:\matcom45\doc\users\_th ...
- Spring中Bean实例的生命周期及其行为
- java新手笔记11 类的静态属性、方法(单例)
1.Person类 package com.yfs.javase; public class Person { String name;//每个对象上分配 与对象绑定 int age; char se ...
- Codevs 1648 最大和
1648 最大和 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description N个数围成一圈,要求从中选择若干个连续的数(注意每个 ...
- References & the Copy-Constructor
1 There are certain rules when using references: (Page 451) A reference must be initialized when it ...