P4088 [USACO18FEB]Slingshot 线段树+扫描线
\(\color{#0066ff}{ 题目描述 }\)
Farmer John最讨厌的农活是运输牛粪。为了精简这个过程,他产生了一个新奇的想法:与其使用拖拉机拖着装满牛粪的大车从一个地点到另一个地点,为什么不用一个巨大的便便弹弓把牛粪直接发射过去呢?(事实上,好像哪里不太对……) Farmer John的农场沿着一条长直道路而建,所以他农场上的每个地点都可以简单地用该地点在道路上的位置来表示(相当于数轴上的一个点)。FJ建造了\(N\)个弹弓(\(1 \leq N \leq 10^5\)),其中第\(i\)个弹弓可以用三个整数\(x_i\),\(y_i\)以及\(t_i\)描述,表示这个弹弓可以在\(t_i\)单位时间内将牛粪从位置\(x_i\)发射到位置\(y_i\)。
FJ有\(M\)堆牛粪需要运输(\(1 \leq M \leq 10^5\))。第\(j\)堆牛粪需要从位置\(a_j\)移动到位置\(b_j\)。使用拖拉机运输牛粪,经过路程\(d\)需要消耗\(d\)单位时间。FJ希望通过对每一堆牛粪使用至多一次弹弓来减少运输时间。FJ驾驶没有装载牛粪的拖拉机的时间不计。
对这\(M\)堆牛粪的每一堆,在FJ可以在运输过程中使用至多一次弹弓的条件下,帮助FJ求出其最小运输时间。
\(\color{#0066ff}{输入格式}\)
输入的第一行包含\(N\)和\(M\)。下面\(N\)行,每行用\(x_i\),\(y_i\),\(t_i\)(\(0 \leq x_i, y_i, t_i \leq 10^9\))描述了一个弹弓。最后\(M\)行用\(a_j\)和\(b_j\)描述了需要移动的牛粪。
\(\color{#0066ff}{输出格式}\)
输出\(M\)行,每堆牛粪一行,表示运输这堆牛粪需要的最短时间。
\(\color{#0066ff}{输入样例}\)
2 3
0 10 1
13 8 2
1 12
5 2
20 7
\(\color{#0066ff}{输出样例}\)
4
3
10
\(\color{#0066ff}{数据范围与提示}\)
none
\(\color{#0066ff}{ 题解 }\)
我们设弹弓是从x到y,询问从l到r
那么如果不加弹弓,代价是\(|r-l|\)
如果借助弹弓,显然是\(|r-y|+|l-x|+t\)
看到绝对值,要想办法去掉
于是出现了4种情况
这里拿其中一种情况举个锤子(雾
当\(r\ge y 且l\ge x\)时,拆开,\(r-y+l-x+t=l+r-x-y+t\)
于是我们把询问和弹弓的端点都离散化,并按照r排序
枚举询问,维护一个在弹弓上的指针,把所有小于当前询问r的y都加入线段树中
以\(x\)为下标,插入\(-x-y+t\),经过排序,显然第一个条件已经满足,于是我们线段树上查询\([1,l]\)的答案再加上\(l\)和\(r\)即可
其余情况分类讨论,同理
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const LL inf = 999999999999999LL;
const int maxn = 6e5 + 100;
struct Tree {
protected:
struct node {
node *ch[2];
int l, r;
LL min;
node(int l = 0, int r = 0, LL min = inf): l(l), r(r), min(min) {}
void *operator new(size_t) {
static node *S = NULL, *T = NULL;
return (S == T) && (T = (S = new node[1024]) + 1024), S++;
}
void upd() { min = std::min(ch[0]->min, ch[1]->min); }
};
node *root;
void build(node *&o, int l, int r) {
o = new node(l, r, inf);
if(l == r) return;
int mid = (l + r) >> 1;
build(o->ch[0], l, mid), build(o->ch[1], mid + 1, r);
}
void lazy(node *o, int p, LL k) {
if(o->r < p || o->l > p) return;
if(o->l == o->r) return (void)(o->min = std::min(o->min, k));
lazy(o->ch[0], p, k), lazy(o->ch[1], p, k);
o->upd();
}
LL query(node *o, int l, int r) {
if(o->r < l || o->l > r) return inf;
if(l <= o->l && o->r <= r) return o->min;
return std::min(query(o->ch[0], l, r), query(o->ch[1], l, r));
}
void clr(node *o) {
o->min = inf;
if(o->l == o->r) return;
clr(o->ch[0]), clr(o->ch[1]);
}
public:
void build(int n) { build(root, 1, n); }
void lazy(int p, LL k) { lazy(root, p, k); }
LL query(int l, int r) { return query(root, l, r); }
void clr() { clr(root); }
}s;
struct Q {
int x, y;
LL val;
Q(int x = 0, int y = 0, LL val = 0): x(x), y(y), val(val) {}
friend bool operator < (const Q &a, const Q &b) {
return a.y == b.y? a.x < b.x : a.y < b.y;
}
}q[maxn], d[maxn];
int n, m;
LL a[maxn];
LL ans[maxn];
int main() {
n = in(), m = in();
int x, y, t, len = 0;
for(int i = 1; i <= n; i++) {
x = in(), y = in(), t = in();
d[i] = Q(x, y, t);
a[++len] = x, a[++len] = y;
}
for(int i = 1; i <= m; i++) {
x = in(), y = in();
q[i] = Q(x, y, i);
a[++len] = x, a[++len] = y;
ans[i] = y > x? y - x : x - y;
}
std::sort(a + 1, a + len + 1);
int _ = 1;
for(int i = 2; i <= len; i++) if(a[i] != a[i - 1]) a[++_] = a[i];
len = _;
s.build(len);
for(int i = 1; i <= n; i++) {
d[i].x = std::lower_bound(a + 1, a + len + 1, d[i].x) - a;
d[i].y = std::lower_bound(a + 1, a + len + 1, d[i].y) - a;
}
for(int i = 1; i <= m; i++) {
q[i].x = std::lower_bound(a + 1, a + len + 1, q[i].x) - a;
q[i].y = std::lower_bound(a + 1, a + len + 1, q[i].y) - a;
}
std::sort(d + 1, d + n + 1);
std::sort(q + 1, q + m + 1);
int now = 1;
for(int i = 1; i <= m; i++) {
while(now <= n && d[now].y <= q[i].y) {
s.lazy(d[now].x, - a[d[now].x] - a[d[now].y] + d[now].val);
now++;
}
ans[q[i].val] = std::min(ans[q[i].val], a[q[i].x] + a[q[i].y] + s.query(1, q[i].x));
}
now = 1, s.clr();
for(int i = 1; i <= m; i++) {
while(now <= n && d[now].y <= q[i].y) {
s.lazy(d[now].x, a[d[now].x] - a[d[now].y] + d[now].val);
now++;
}
ans[q[i].val] = std::min(ans[q[i].val], - a[q[i].x] + a[q[i].y] + s.query(q[i].x, len));
}
now = n, s.clr();
for(int i = m; i >= 1; i--) {
while(now >= 1 && d[now].y >= q[i].y) {
s.lazy(d[now].x, - a[d[now].x] + a[d[now].y] + d[now].val);
now--;
}
ans[q[i].val] = std::min(ans[q[i].val], a[q[i].x] - a[q[i].y] + s.query(1, q[i].x));
}
now = n, s.clr();
for(int i = m; i >= 1; i--) {
while(now >= 1 && d[now].y >= q[i].y) {
s.lazy(d[now].x, a[d[now].x] + a[d[now].y] + d[now].val);
now--;
}
ans[q[i].val] = std::min(ans[q[i].val], - a[q[i].x] - a[q[i].y] + s.query(q[i].x, len));
}
for(int i = 1; i <= m; i++) printf("%lld\n", ans[i]);
return 0;
}
P4088 [USACO18FEB]Slingshot 线段树+扫描线的更多相关文章
- LUOGU P4088 [USACO18FEB]Slingshot(线段树)
传送门 解题思路 推了推式子发现是个二维数点,想了想似乎排序加线段树难写,就写了个树套树,结果写完看见空间才\(128M\)..各种奇技淫巧卡空间还是\(MLE\)到天上.后来只好乖乖的写排序+线段树 ...
- 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)
D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...
- Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)
题目链接:http://codeforces.com/contest/522/problem/D 题目大意: 给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...
- 【POJ-2482】Stars in your window 线段树 + 扫描线
Stars in Your Window Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11706 Accepted: ...
- HDU 4419 Colourful Rectangle --离散化+线段树扫描线
题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...
- BZOJ-3228 棋盘控制 线段树+扫描线+鬼畜毒瘤
3228: [Sdoi2008]棋盘控制 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 23 Solved: 9 [Submit][Status][D ...
- BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞
看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...
- hdu 5091(线段树+扫描线)
上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...
- POJ1151+线段树+扫描线
/* 线段树+扫描线+离散化 求多个矩形的面积 */ #include<stdio.h> #include<string.h> #include<stdlib.h> ...
随机推荐
- scrapy-redis源码抛析
#scrapy-redis--->queue.py-->class FifoQueue 队列 LifoQueue(lastinfirstout栈) #self.server父类Base中链 ...
- 12-18Windows窗体应用小程序之记事本(1)
一.记事本制作(1) C#结合窗体制作小程序,相比较之前的控制台应用程序可能要改善了好多,最起码界面看起来可以高仿一下了,但是最重要的还是要看其里面的功能是否实现.所以,要以实现其实用功能为主.今天利 ...
- sea.js的模块化开发
为什么使用sea.js? Sea.js 追求简单.自然的代码书写和组织方式,具有以下核心特性: 简单友好的模块定义规范:Sea.js 遵循 CMD 规范,可以像Node.js 一般书写模块代码. 自然 ...
- render tree与css解析
浏览器在构造DOM树的同时也在构造着另一棵树-Render Tree,与DOM树相对应暂且叫它Render树吧,我们知道DOM树为javascript提供了一些列的访问接口(DOM API),但这棵树 ...
- js语法和数据类型
基础知识(Basics) JavaScript 的很多语法借鉴自 Java,但也受 Awk,Perl 和 Python 影响. JavaScript 是大小写敏感的,使用 Unicode 字符集. 在 ...
- php中COM函数的使用
php里的com类可以操作window系统上的东西 例如:可以在本地打开一个word文档,然后写入东西,只用于window系统 需要加载php_com_dotnet.dll模块 $word = n ...
- js面试题知识点全解(一原型和原型链)
1.如何准确判断一个变量是数组类型2.写一个原型链继承的例子3.描述new一个对象的过程4.zepto(或其他框架)源码中如何使用原型链知识点:1.构造函数2.构造函数-扩展3.原型规则和示例4.原型 ...
- ES6中的Set与Map数据结构
本文实例讲述了ES6学习笔记之Set和Map数据结构.分享给大家供大家参考,具体如下: 一.Set ES6提供了新的数据结构Set.类似于数组,只不过其成员值都是唯一的,没有重复的值. Set本身是一 ...
- 624. Maximum Distance in Arrays二重数组中的最大差值距离
[抄题]: Given m arrays, and each array is sorted in ascending order. Now you can pick up two integers ...
- Windows系统 安装 CMake
Windows系统 安装 CMake 我们的电脑系统:Windows 10 64位 安装的CMake 版本:cmake-3.6.1-win64-x64(目前最新) 下载 在CMake官网下载:cmak ...