#线段树分治,凸壳#洛谷 5416 [CTSC2016]时空旅行
题目大意
有 \(n\) 个平行宇宙,由某些平行宇宙添加或删除一个点(三维坐标)得到,
现在有 \(m\) 组询问,形如对于某个平行宇宙,费用为从该平行宇宙内某个点出发
到达指定 \(x\) 坐标的任意位置的欧几里得距离,
并且这些点本身出发需要费用,如何让费用最小,
保证原点在所有平行宇宙中均存在
解题过程
首先 \(x\) 坐标指定那么其实 \(y\) 坐标和 \(z\) 坐标可以被忽略,
那么询问可以转化为形如找到一个存在的 \(x\) ,
使得 \(y=(x-x_0)^2+d\)最小,其中\(d\)表示从这个 \(x\) 出发本身所需费用
把这个平方拆开可以得到 \(y=x^2-2x\cdot x_0 + {x_0}^2+d\)
将常数项放前面可以得到 \({x_0}^2=2x_0\cdot x-x^2+y-d\)
也就是各点坐标为\((2x,-x^2+d)\),用斜率为 \(x_0\) 的直线扫描使得截距最小,那么这也就是求一个下凸壳
然后考虑平行宇宙怎么做,它会形成一棵树,那么点的存在就会锁定在一些dfs序的连续区间中,
也就可以转化成线段树维护dfs序的区间,点按横坐标为第一关键字,纵坐标为第二关键字排序,
如果强制在线询问的话那么就二分答案需要多带一个\(\log\),
否则可以按照斜率排序那么直接删除队头即可,时间复杂度\(O(m\log_2n)\)
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#define rr register
using namespace std;
const int N = 500011;
typedef long long lll;
struct Point {
lll x, y;
inline Point operator -(const Point &t)const {
return (Point) {
x - t.x, y - t.y
};
}
} a[N];
struct rec {
int x, z, rk;
} q[N];
struct node {
int y, next;
} e[N];
vector<int>L[N], R[N];
vector<Point>K[N << 2];
lll ans[N];
int n, m, Q, rk[N], head[N << 2], dfn[N], et, v[N], tot, Z[N], as[N];
inline lll input() {
rr lll ans = 0, f = 1;
rr char c = getchar();
while (!isdigit(c))
f = (c == '-') ? -f : f, c = getchar();
while (isdigit(c))
ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
return ans * f;
}
inline void print(lll ans) {
if (ans < 0)
putchar('-'), ans = -ans;
if (ans > 9)
print(ans / 10);
putchar(ans % 10 + 48);
}
inline lll dj(Point x, Point y) {//数量积
return x.x * y.x + x.y * y.y;
}
inline lll cj(Point x, Point y) {//向量积
return x.x * y.y - x.y * y.x;
}
inline void add(int x, int y) {
e[++et] = (node) {y, as[x]}, as[x] = et;
}
inline void update(int k, int l, int r, int x, int y, int z) {
if (l == x && r == y) {
while (K[k].size() > 1 && cj(a[z] - K[k][K[k].size() - 1], a[z] - K[k][K[k].size() - 2]) <= 0)
K[k].pop_back();//下凸壳,也就是向量积为顺时针时弹出队尾
K[k].push_back(a[z]);
return;
}
rr int mid = (l + r) >> 1;
if (y <= mid)
update(k << 1, l, mid, x, y, z);
else if (x > mid)
update(k << 1 | 1, mid + 1, r, x, y, z);
else
update(k << 1, l, mid, x, mid, z), update(k << 1 | 1, mid + 1, r, mid + 1, y, z);
}
inline lll kxb(lll k, Point x) {//实际答案
return k * x.x + x.y;
}
inline lll query(int k, int l, int r, int x, int z) {
rr int len = K[k].size();
rr lll ans = -2e18;
if (len) {
while (head[k] < len - 1 && kxb(z, K[k][head[k]]) <= kxb(z, K[k][head[k] + 1]))
++head[k];
ans = kxb(z, K[k][head[k]]);
}
if (l == r)
return ans;
rr int mid = (l + r) >> 1;
if (x <= mid)
return max(ans, query(k << 1, l, mid, x, z));
else
return max(ans, query(k << 1 | 1, mid + 1, r, x, z));
}
inline void dfs(int x) {
dfn[x] = ++tot;
if (Z[x] > 0)
L[Z[x]].push_back(tot);//插入操作的开头
if (Z[x] < 0)
R[-Z[x]].push_back(tot - 1);//删除操作的结尾
for (rr int i = as[x]; i; i = e[i].next)
dfs(e[i].y);
if (Z[x] > 0)
R[Z[x]].push_back(tot);//插入操作的结尾
if (Z[x] < 0)
L[-Z[x]].push_back(tot + 1);//删除操作的开头
}
bool cmp1(int x, int y) {//横坐标第一关键字
return a[x].x < a[y].x || (a[x].x == a[y].x && a[x].y < a[y].y);
}
bool cmp2(rec x, rec y) {//按斜率排序
return x.z < y.z;
}
signed main() {
freopen("travel.in", "r", stdin);
freopen("travel.out", "w", stdout);
n = input(), Q = input(),
L[1].push_back(1),
R[1].push_back(n), v[1] = 1;
a[m = 1] = (Point) {
0, -input()
};
//令第一个点为原点
for (rr int i = 2; i <= n; ++i) {
rr int opt = iut();
add(input() + 1, i);
rr int z = input() + 2;
if (!v[z])
v[z] = ++m;//重新编号
if (opt == 1)
Z[i] = -v[z];//删除操作
else {
rr lll d = iut();
input(), input();
a[Z[i] = v[z]] = (Point) {
2 * d, -d *d - input()
};//添加点
}
}
for (rr int i = 1; i <= m; ++i)
rk[i] = i;
dfs(1), sort(rk + 1, rk + 1 + m, cmp1);
for (rr int i = 1; i <= m; ++i) {
rr int len = L[rk[i]].size();
for (rr int j = 0; j < len; ++j) {
rr int Ll = L[rk[i]][j], Rr = R[rk[i]][j];
if (Ll <= Rr)
update(1, 1, n, Ll, Rr, rk[i]);
}
}
for (rr int i = 1; i <= Q; ++i)
q[i] = (rec) {
dfn[input() + 1], input(), i
};
sort(q + 1, q + 1 + Q, cmp2);
for (rr int i = 1; i <= Q; ++i)
ans[q[i].rk] = 1ll * q[i].z * q[i].z - query(1, 1, n, q[i].x, q[i].z);
for (rr int i = 1; i <= Q; ++i)
print(ans[i]), putchar(10);
return 0;
}
#线段树分治,凸壳#洛谷 5416 [CTSC2016]时空旅行的更多相关文章
- 线段树分治初步学习&洛谷P5227[AHOI2013]连通图
线段树分治 其实思想说起来是比较简单的,我们把这个题里的所有操作(比如连边删边查询balabala)全部拍到一棵线段树上,然后对着整棵树dfs一下求解答案,顺便把操作做一下,回溯的时候撤销一下即可.虽 ...
- bzoj2402 陶陶的难题II 分数规划+树剖+线段树维护凸壳+二分
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2402 题解 看上去很像分数规划的模型.于是就二分吧.令 \[ \begin{align*}\f ...
- 李超线段树(segment[HEOI2013]-洛谷T4097)
(neng了好久好久才糊弄懂得知识点...) 一.李超线段树 在线动态维护一个二维平面直角坐标系, 支持插入一条线段, 询问与直线x = x0相交的所有线段中,交点y的最大/小值 (若有多条线段符合条 ...
- 线段树板子1(洛谷P3372)
传送 一道线段树板子(最简单的) 似乎之前在培训里写过线段树的样子?不记得了 何为线段树? 一般就是长成这样的树,树上的每个节点代表一个区间.线段树一般用于区间修改,区间查询的问题. 我们如何种写一棵 ...
- 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)
LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...
- Bzoj1018/洛谷P4246 [SHOI2008]堵塞的交通(线段树分治+并查集)
题面 Bzoj 洛谷 题解 考虑用并查集维护图的连通性,接着用线段树分治对每个修改进行分治. 具体来说,就是用一个时间轴表示图的状态,用线段树维护,对于一条边,我们判断如果他的存在时间正好在这个区间内 ...
- 【洛谷4219】[BJOI2014]大融合(线段树分治)
题目: 洛谷4219 分析: 很明显,查询的是删掉某条边后两端点所在连通块大小的乘积. 有加边和删边,想到LCT.但是我不会用LCT查连通块大小啊.果断弃了 有加边和删边,还跟连通性有关,于是开始yy ...
- LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset
题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ...
- 洛谷 P2147 [SDOI2008]洞穴勘测 (线段树分治)
题目链接 题解 早就想写线段树分治的题了. 对于每条边,它存在于一段时间 我们按时间来搞 我们可把一条边看做一条线段 我们可以模拟线段树操作,不断分治下去 把覆盖\(l-r\)这段时间的线段筛选出来, ...
- 【洛谷4585】[FJOI2015] 火星商店问题(线段树分治)
点此看题面 大致题意: 有\(n\)家店,每个商品有一个标价.每天,都可能有某家商店进货,也可能有某人去购物.一个人在购物时,会于编号在区间\([L_i,R_i]\)的商店里挑选一件进货\(d_i\) ...
随机推荐
- pep8相关规范
https://www.jianshu.com/p/ffcc66bab3ce 导包规范: 1.首先是标准库,如 import os 2.然后是第三方库,如 from django.conf impor ...
- 手动下载sdk及avd
有时候下载sdk的时候报各种错误导致无法下载,如图 那么可以离线下载,到浏览器或IDM中下载图中提示的url链接,将第一个下载的包即sources的解压后放到SDK目录下的sources目录,并重命名 ...
- 最小生成树(二)Prim算法
一.思想 1.1 基本概念 加权无向图的生成树:一棵含有其所有顶点的无环连通子图. 最小生成树(MST):一棵权值最小(树中所有边的权值之和)的生成树. 1.2 算法原理 1.2.1 切分定理 切分定 ...
- [.Net 6]写一个简单的文件上传控件后端
此项目是配合上一篇文章[Vue]写一个简单的文件上传控件 - 林晓lx - 博客园 (cnblogs.com) 的后端程序,使用.Net 6项目框架搭建,开发前请安装Visual Studio 20 ...
- private priv 私人 pri=prim first v=self 自己第一
private priv 私人 pri=prim first v=self 自己第一 private v自己-私人的 pri 来自PIE*per,向前,穿过 pri = pre 向前(这么理解也说的过 ...
- Windows逆向之配置虚拟机环境
安装虚拟机环境 首先下载吾爱破解论坛专用版虚拟机软件VMWare Workstation 12,注册成功:再通过虚拟机启动论坛提供的WinXP系统镜像,在我的win11上完美运行. 实现文件互传 为了 ...
- 音频信号质量的度量标准--MOS得分的由来
早期语音质量的评价方式是凭主观的,人们在打通电话之后通过人耳来感知语音质量的好坏.1996年国际ITU组织在ITU-T P.800和P.830建议书开始制订相关的评测标准:MOS(Mean Opini ...
- vue入门教程之-插槽
vue入门教程之-插槽 欢迎关注博主公众号「java大师」, 专注于分享Java领域干货文章, 关注回复「资源」, 免费领取全网最热的Java架构师学习PDF, 转载请注明出处 https://www ...
- day04-实现SpringBoot底层机制
实现SpringBoot底层机制 Tomcat底层启动分析+Spring容器初始化+Tomcat关联Spring容器 1.任务1-创建Tomcat,并启动 (1)创建一个Maven项目,修改pom.x ...
- C程序问题归纳(static,auto,register,extern,程序内存分布图,linux下程序的执行过程......)(二)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...