@description@

2045 年,人类的技术突飞猛进,已经找到了进行时空旅行的方法。小 R 得到了一台时空旅行仪,他想用它调查不同时空中人类的发展状况。

根据平行时空理论,宇宙中存在着很多独立的时空,每个时空在下一个时间点还会分化出若干个不同的时空。宇宙是一个三维空间,人类使用空间直角坐标系来描述空间中的一个位置,三维坐标分别是 x,y,z。

我们假设在初始的时空(编号为 0)中,人类存在于地球上(地球的坐标为 (0,0,0)),其他的时空都是从一个现有的时空发展而来的。一个时空发生一个时间之后会发展成为另外一个时空(原来的时空不发生任何变化)。会影响小 R 的时间包括两类:

人类殖民了一个新的星球,该星球的状态变成“已被殖民”。

人类放弃了一个已被殖民的星球,该星球的状态变成“未被殖民”。

每次进行时空旅行时,小 R 会先选定一个时空。在这个时空中,人类已经殖民了一些星球。小 R 只要到达该时空中任意一个已被殖民的星球,就能调查人类的发展状况。

小 R 的时空旅行仪出现了一些问题,调整 x 坐标的按钮坏掉了,因此到达点的 x 坐标被固定了(每次旅行的 x 坐标值可能不同)。与此同时,他仍能任意调整到达点的 y 坐标和 z 坐标。

这个问题大大增大了小 R 的花费:因为时空旅行没有花费,但在太空中航行却需要花钱;同时,在不同星球进行调查也可能会产生不同的费用。

假设小 R 将时空旅行的终点设为 A,他要进行调查的星球为 B:如果 A 与 B 的欧几里得距离为 d,那么他太空航行的花费就是 d^2;又如果星球 B 上进行调查的费用为 c,那么小 R 此次调查的总花费就是 d^2 + c。

现在给定小 R 每次旅行到达的时空以及时空旅行仪上固定的 x 坐标值,请你计算出小 R 每次旅行完成调查的最小总花费。

原题传送门。

@solution@

首先不难发现 y, z 都是来唬你的,其实代价函数为 (xi - x0)^2 + ci;接着你发现代价函数是个明显的斜率优化。

考虑一个点的影响范围:它第一次被加入的位置对应的子树 T,扣掉它被删除的位置集合 S 对应的子树集合 Ts。

可以用 dfs 序把影响范围拆解成若干区间。如果该点被删除了 x 次,则会产生最多 x + 1 个区间。

注意到一个树点恰好对应增/删一次,所以拆解出来的区间总数是 O(n) 的。

那么问题转化成:首先区间加点,然后单点询问凸包。

如果我们把 dfs 序看成从左往右的时间轴,则可以变成凸包加/删点,给定斜率进行询问。

凸包并不能删点(李超线段树也不行),所以考虑一个不用能把删除去掉辅助的算法,比如线段树分治(当然这一步并不是必需的转化,你可以直接联想到线段树)。

使用线段树分治后,线段树上每一个结点有着若干点以及若干询问。

如果使用在每个结点内部使用 O(nlogn) 的算法,总复杂度为 O(nlog^2n)。

考虑在最外层排好序后再插入到线段树中,这样最终线段树上每一个结点内部的点集与询问都是有序的,直接单调队列可以做到 O(n)。

因此总复杂度 O(nlogn)。

@accepted code@

  1. #include <cstdio>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespace std;
  5. const int MAXN = 500000;
  6. const double INF = 1E18;
  7. typedef long long ll;
  8. ll ans[MAXN + 5]; int n, m;
  9. struct point{
  10. ll x, y; point() {}
  11. point(ll _x, ll _y) : x(_x), y(_y) {}
  12. friend bool operator < (const point &a, const point &b) {
  13. return (a.x == b.x ? a.y < b.y : a.x < b.x);
  14. }
  15. };
  16. struct query{
  17. ll k; int id, pos; query() {}
  18. query(ll _k, int _i) : k(_k), id(_i) {}
  19. friend bool operator < (const query &a, const query &b) {
  20. return a.k < b.k;
  21. }
  22. }b[MAXN + 5];
  23. struct node{
  24. int l, r; point p; node() {}
  25. node(int _l, int _r, point _p) : l(_l), r(_r), p(_p) {}
  26. friend bool operator < (const node &a, const node &b) {
  27. return a.p < b.p;
  28. }
  29. }a[2*MAXN + 5]; int acnt;
  30. #define lch (x << 1)
  31. #define rch (x << 1 | 1)
  32. int le[4*MAXN + 5], ri[4*MAXN + 5];
  33. vector<int>v1[4*MAXN + 5], v2[4*MAXN + 5];
  34. void build(int x, int l, int r) {
  35. le[x] = l, ri[x] = r;
  36. if( l == r ) return ;
  37. int m = (l + r) >> 1;
  38. build(lch, l, m), build(rch, m + 1, r);
  39. }
  40. void insert(int x, int l, int r, int k) {
  41. if( r < le[x] || l > ri[x] )
  42. return ;
  43. if( l <= le[x] && ri[x] <= r ) {
  44. v1[x].push_back(k);
  45. return ;
  46. }
  47. insert(lch, l, r, k), insert(rch, l, r, k);
  48. }
  49. void add(int x, int p, int k) {
  50. v2[x].push_back(k);
  51. if( le[x] == ri[x] ) return ;
  52. int m = (le[x] + ri[x]) >> 1;
  53. add(p <= m ? lch : rch, p, k);
  54. }
  55. point que[MAXN + 5];
  56. double slope(point a, point b) {
  57. if( a.x == b.x )
  58. return a.y < b.y ? INF : -INF;
  59. else return 1.0 *(a.y - b.y) / (a.x - b.x);
  60. }
  61. void get(int x) {
  62. int s = 1, t = 0;
  63. for(int i=0;i<v1[x].size();i++) {
  64. point p = a[v1[x][i]].p;
  65. if( s <= t && que[t].x == p.x && que[t].y == p.y ) continue;
  66. while( s < t && slope(que[t - 1], que[t]) >= slope(que[t], p) )
  67. t--;
  68. que[++t] = p;
  69. }
  70. for(int i=0;i<v2[x].size();i++) {
  71. int id = b[v2[x][i]].id; ll k = b[v2[x][i]].k;
  72. while( s < t && slope(que[s], que[s + 1]) <= k )
  73. s++;
  74. if( s <= t ) ans[id] = min(ans[id], que[s].y - k*que[s].x + k*k);
  75. }
  76. }
  77. void solve(int x) {
  78. get(x);
  79. if( le[x] == ri[x] ) return ;
  80. solve(lch), solve(rch);
  81. }
  82. int x[MAXN + 5]; ll c[MAXN + 5];
  83. point pnt(int i) {
  84. return point(2*x[i], 1LL*x[i]*x[i] + c[i]);
  85. }
  86. struct edge{
  87. int to; edge *nxt;
  88. }edges[MAXN + 5], *adj[MAXN + 5], *ecnt = edges;
  89. void addedge(int u, int v) {
  90. edge *p = (++ecnt);
  91. p->to = v, p->nxt = adj[u], adj[u] = p;
  92. }
  93. bool type[MAXN + 5]; int id[MAXN + 5], fa[MAXN + 5];
  94. int dfn[MAXN + 5], tid[MAXN + 5], dcnt;
  95. int nw[MAXN + 5];
  96. void dfs(int x) {
  97. tid[x] = dcnt, dfn[dcnt++] = x;
  98. if( !type[x] ) nw[id[x]] = tid[x];
  99. else a[++acnt] = node(nw[id[x]], tid[x] - 1, pnt(id[x]));
  100. for(edge *p=adj[x];p;p=p->nxt) {
  101. dfs(p->to);
  102. }
  103. if( !type[x] ) a[++acnt] = node(nw[id[x]], dcnt - 1, pnt(id[x]));
  104. else nw[id[x]] = dcnt;
  105. }
  106. int readi() {
  107. int x = 0, f = 1; int ch = getchar();
  108. while( (ch != '-') && (ch > '9' || ch < '0') ) ch = getchar();
  109. if( ch == '-' ) f = -1, ch = getchar();
  110. while( '0' <= ch && ch <= '9' ) x = 10*x + ch - '0', ch = getchar();
  111. return x * f;
  112. }
  113. ll readl() {
  114. ll x = 0; int ch = getchar();
  115. while( ch > '9' || ch < '0' ) ch = getchar();
  116. while( '0' <= ch && ch <= '9' ) x = 10*x + ch - '0', ch = getchar();
  117. return x;
  118. }
  119. void write(ll x) {
  120. if( !x ) return ;
  121. write(x / 10);
  122. putchar(x % 10 + '0');
  123. }
  124. int main() {
  125. freopen("travel.in", "r", stdin);
  126. freopen("travel.out", "w", stdout);
  127. n = readi(), m = readi(), c[0] = readl(), type[0] = id[0] = 0;
  128. for(int i=1;i<n;i++) {
  129. type[i] = readi(), fa[i] = readi(), id[i] = readi();
  130. if( type[i] == 0 )
  131. x[id[i]] = readi(), readi(), readi(), c[id[i]] = readl();
  132. addedge(fa[i], i);
  133. }
  134. build(1, 0, n - 1), dfs(0);
  135. sort(a + 1, a + acnt + 1);
  136. for(int i=1;i<=acnt;i++)
  137. insert(1, a[i].l, a[i].r, i);
  138. for(int i=1;i<=m;i++) {
  139. int s = readi(), x0 = readi();
  140. ans[i] = INF, b[i] = query(x0, i), b[i].pos = tid[s];
  141. }
  142. sort(b + 1, b + m + 1);
  143. for(int i=1;i<=m;i++)
  144. add(1, b[i].pos, i);
  145. solve(1);
  146. for(int i=1;i<=m;i++)
  147. write(ans[i]), puts("");
  148. }

@details@

没事儿不要在这种大数据范围情况下用 vector。

第一次直接存点和询问用 vector 结果 MLE 了,后来改成存点和询问的编号虽然 AC 了,但是常数还是比较大。

@loj - 2987@ 「CTSC2016」时空旅行的更多相关文章

  1. Loj #3057. 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

  2. LOJ 3057 「HNOI2019」校园旅行——BFS+图等价转化

    题目:https://loj.ac/problem/3057 想令 b[ i ][ j ] 表示两点是否可行,从可行的点对扩展.但不知道顺序,所以写了卡时间做数次 m2 迭代的算法,就是每次遍历所有不 ...

  3. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  4. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  5. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  6. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  7. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  8. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  9. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

随机推荐

  1. 201771010128 王玉兰《面象对象程序设计(Java)》第六周学习总结

    第一部分:基础知识总结: 1.继承 A:用已有类来构建新类的一种机制,当定义了一个新类继承一个类时,这个新类就继承了这个类的方法和域以适应新的情况: B:特点:具有层次结构.子类继承父类的方法和域: ...

  2. 蓝桥杯 试题 历届试题 对局匹配 DP解决

    问题描述 小明喜欢在一个围棋网站上找别人在线对弈.这个网站上所有注册用户都有一个积分,代表他的围棋水平. 小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是K的两名用户匹配在一起.如果两人分差 ...

  3. Java——日期获取和日期格式化

    import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; impor ...

  4. Java连接MySql报错—— com.mysql.cj.exceptions.InvalidConnectionAttributeException

    详细报错 java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents mor ...

  5. Ant Design of Vue 组件库的使用

    文档里面很清楚 安装步骤    这是全部引入的 1  有的组价涉及到汉化的问题 import moment from 'moment' import '../../../../node_modules ...

  6. 「Java面试题/知识点精华集」20000+字的Java基础知识篇(2020最新版) !

    本文已经收录进我的 79K Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java学习+面试指南」一份涵盖大 ...

  7. pytest跟unittest的优势跟劣势

    一.用例编写规则 1.使用unittest编写测试用例必须遵循以下规则: 1.必须首先 导入 import unittest 2.测试类必须要继承 unittest.TestCase 3.测试方法必须 ...

  8. Istio 流量劫持过程

    开篇 Istio 流量劫持的文章其实目前可以在servicemesher社区找到一篇非常详细的文章,可查阅:Istio 中的 Sidecar 注入及透明流量劫持过程详解.特别是博主整理的那张" ...

  9. (八)Filter&ThreadLocal实现处理事务

    ConnectionContext.java package com.aff.bookstore.web; import java.sql.Connection; public class Conne ...

  10. RocketMQ系列(一)基本概念

    RocketMQ是阿里出品的一款开源的消息中间件,让其声名大噪的就是它的事务消息的功能.在企业中,消息中间件选择使用RocketMQ的还是挺多的,这一系列的文章都是针对RocketMQ的,咱们先从Ro ...