\(\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. 开发工具:sublime text3安装Vue语法高亮插件

    一.将插件克隆到Sublime的packages目录 1.下载并解压插件(或直接git命令clone),得到vue-syntax-highlight-master文件夹 插件地址:https://gi ...

  2. 发任务找不到test-unit报错

    发任务的时候因找不到gem包test-unit报错, 出错行: require 'test/unit' require 'test/unit/testresult' 解决办法如下 1.通过命令查看ge ...

  3. 开发环境入门 linux基础 基本操作命令(部分) 文本结构和基本命令

    文本结构和基本命令 linux系统中系统提示符:$ 表示普通用户 su  root切换用户命令(用户名 root),输入密码,切换到其他用户状态 root 命令提示符:# exit 退出当前用户,返回 ...

  4. [MySQL]修改mysql数据库的root密码的方法

    方法1: 用SET PASSWORD命令 mysql -u root mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpass ...

  5. 在ACCESS中LIKE的用法

    Access里like的通配符用法是这样:     “?”表示任何单一字符: “*”表示零个或多个字符: “#”表示任何一个数字     所以应该是:     select * from databa ...

  6. Tiny4412 Linux 内核配置流程

    1.配置交叉编译器 默认情况下,内核构建的是与宿主机相同的体系架构镜像.如果要交叉编译,需要设置两个变量ARCH和CORSS_COMPILE. ①ARCH:指明目标体系架构,如x86.arm.mips ...

  7. Yahoo浮沉录

    Yahoo这一路曾经出过很多好技术 然而,任何人如果只是把 Yahoo 当作一家缺乏聚焦的企业来看也许忽视了公司内部的那些创新—偶尔甚至还有一些很好的产品创意.就拿搜索来说吧,我们说的不是付费搜索,而 ...

  8. 【Android异常】The specified child already has a parent. You must call removeView() on the child's parent first.

    错误信息: Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must ...

  9. Android ScrollView 内部控件 layout_margin失效的解决方法

    在<ScrollView> 的<LinearLayout  >属性里面加入android:layout_gravity="top" <LinearLa ...

  10. ascii#ascii,对象类中找__repr__,获取其返回值

    #!/usr/bin/env python #ascii,对象类中找__repr__,获取其返回值 class Foo : def __repr__(self): return "hello ...