\(\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. java中内部类的讲解

    java中有一个内部类的概念,由于之前一直比较忙,没有单独拿出时间总结一下,今天我就把内部类的相关知识进行一下汇总,如果有不足之处,欢迎批评指正. 1)java内部类的概念.       在一个类的的 ...

  2. SQL属性第一个值不被选中,属性默认第一个值

    把 Please Choose Color 属性名设置为不可选的 UPDATE `products_attributes` SET `attributes_display_only` = '1' WH ...

  3. chrome开发者工具的使用

    转自:https://blog.csdn.net/csdnligao/article/details/53925094

  4. MySQL存储引擎 -- MyISAM(表锁定) 与 InnoDB(行锁定) 锁定机制

    前言 为了保证数据的一致完整性,任何一个数据库都存在锁定机制.锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核心技术之一.本章将对MySQL中两种 ...

  5. Ros学习topic——小海龟

    ROS Topics 1.rqt_graph:创建一个显示当前系统运行情况的动态图形 安装 $ sudo apt-get install ros-<distro>-rqt $ sudo a ...

  6. __tostring和__invoke 方法

    首先放上代码: <?php class MagicTest{ //__tostring会在把对象转换为string的时候自动调用 public function __tostring() { r ...

  7. 九款常用的JS代码高亮工具

    代码高亮很重要,特别是当我们想要在网站或博客中展示我们的代码的时候.通过在网站或博客中启用代码高亮,读者更方便的读取代码块. 有很多免费而且有用的代码高亮脚本.这些脚本大部分由Javascripts编 ...

  8. 【转】pecl,pear的不同

    PEAR是PHP扩展与应用库(the PHP Extension and Application Repository)的缩写.它是一个PHP扩展及应用的一个代码仓库,基于php代码的,安装目录在/u ...

  9. (转)C++中使用C代码

    昨晚看书的时候碰到一个问题,在C++中如何调用C代码...于是查了一下资料...发现了一个大神写的文章挺好的. -------------------------------------------- ...

  10. p1129 [ZJOI2007]矩阵游戏

    传送门 分析 不难想到将黑点的行列连边,然后判断最大匹配是否等于n 代码 #include<iostream> #include<cstdio> #include<cst ...