\(\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 线段树+扫描线的更多相关文章

  1. LUOGU P4088 [USACO18FEB]Slingshot(线段树)

    传送门 解题思路 推了推式子发现是个二维数点,想了想似乎排序加线段树难写,就写了个树套树,结果写完看见空间才\(128M\)..各种奇技淫巧卡空间还是\(MLE\)到天上.后来只好乖乖的写排序+线段树 ...

  2. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  3. Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)

    题目链接:http://codeforces.com/contest/522/problem/D 题目大意:  给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...

  4. 【POJ-2482】Stars in your window 线段树 + 扫描线

    Stars in Your Window Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11706   Accepted:  ...

  5. HDU 4419 Colourful Rectangle --离散化+线段树扫描线

    题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...

  6. BZOJ-3228 棋盘控制 线段树+扫描线+鬼畜毒瘤

    3228: [Sdoi2008]棋盘控制 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 23 Solved: 9 [Submit][Status][D ...

  7. BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞

    看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...

  8. hdu 5091(线段树+扫描线)

    上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...

  9. POJ1151+线段树+扫描线

    /* 线段树+扫描线+离散化 求多个矩形的面积 */ #include<stdio.h> #include<string.h> #include<stdlib.h> ...

随机推荐

  1. 虚幻引擎4设置Visual Studio

    转自:http://www.unrealchina.net/portal.php?mod=view&aid=149 设置Visual Studio和虚幻引擎4协同工作有利于提高开发人员使用UE ...

  2. 用nfs挂载内核时出错 ERROR: Cannot umount的解决办法

    SMDK2440 # nfs 30000000 192.168.1.106:/work/nfs_root/uImage                         ERROR: resetting ...

  3. Python代码规范总结

    1.缩进问题: Tip:用4个空格来缩进代码 不要用Tab键或者是Tab和空格混用, vim用户可以将tab键设置为4个空格的长度.要么选择垂直对齐换行的元素, 或者是使用4空格悬挂式缩进(第一行没有 ...

  4. 第十六章 Velocity工作原理解析(待续)

    Velocity总体架构 JJTree渲染过程解析 事件处理机制 常用优化技巧 与JSP比较 设计模式解析之合成模式 设计模式解析之解释器模式

  5. composer update的错误使用以及如何更新composer.lock文件

    用composer update装包是错误的. 安装包标准的方法应该是 require ,或者手动写 compose.json 文件,然后 composer install .如果只是需要更新 com ...

  6. centos软件安装目录(amp目录)

    entos安装软件的目录 1. 如果是rpm安装的可以:rpm -ql package-name 2. 可以在根目录上直接find . -name 软件中的某个文件名 不过安装软件一般都在/usr/l ...

  7. 2.《Spring学习笔记-MVC》系列文章,讲解返回json数据的文章共有3篇,分别为:

    转自:https://www.cnblogs.com/ssslinppp/p/4528892.html 个人认为,使用@ResponseBody方式来实现json数据的返回比较方便,推荐使用. 摘要 ...

  8. jquery ajax中error返回错误解决办法

    转自:https://www.jb51.net/article/72198.htm 进入百度搜索此问题,发现有人这么说了一句 Jquery中的Ajax的async默认是true(异步请求),如果想一个 ...

  9. 部署和调优 2.4 tomcat安装

    下载tamcet 官网 http://tomcat.apache.org/ 左侧选择版本 复制下载链接 切换到下载目录 cd /usr/local/src linux wget wget http:/ ...

  10. 关于大数据领域各个组件打包部署到集群运行的总结(含手动和maven)(博主推荐)

    对于这里的打包,总结: (1)     最简单的,也是为了适应公司里,还是要用maven,当然spark那边sbt,maven都可以.但是maven居多. Eclipse/MyEclipse下如何Ma ...