题目链接

Description

维护一个序列,支持操作:

  • 每次在 \(P_i\) 位置后插入一段 \(X_i\) 单位的燃料,这一段有三个模式,对应的能量分别是 \(A_i, B_i, C_i\)。然后将这个序列分成四段(一段可以为空),权值分别是 \(ABCA\),最后求最大总能量。

Solution

首先我们发现一个性质,就是说一段其实在最优解下的状态是相同的,否则可以把状态价值高的蔓延到低的,会更优。

如果不考虑查询,可以把每一段看做一个大小为 \(X_i\) 的点,这个插入操作在时间复杂度能接受的范围内其实是一个平衡树的操作。因为每次插入最坏情况下会分裂一个点,所以点数最多 \(2n\)。我们可以考虑是否能在维护平衡树的时候同步维护答案。

最大总能量显然是 DP,而这道题的 DP 可以写出线性 DP和区间 DP 两种,考虑如果插入一个元素,如果是线性 \(DP\) ,这个元素后面的所有都要重新算一遍,复杂度爆炸。而区间 DP 能够满足我们的要求的。

因为平衡树满足 BST 的性质,所以每个节点的子树可以看做一段区间,每次修改,可以修改的过程同时维护每个节点所在子树区间的答案即可。

状态设计

设 \(f_{i,j}\) 为一个节点所在的子树所形成的区间,状态区间是 \([i, j]\) 所搞成的最大总能量。

初始状态

考虑每个点初始的答案。

$f_{i, j} = X_i \times $ \([i, j]\) 状态中最大的单位权值。

状态转移

考虑一段区间的合并,设左边的为 \(A.f\),右边的是 \(B.f\),答案是 \(C.f\)

有 \(C.f_{i, j} = \max(A.f_{i, k} + B.f_{k, j} )\) 。

在真正实现的时候,先让 $A = $ 左儿子, $B = $当前节点,合并后再合并右儿子即可,合并顺序不影响答案。

时间复杂度

因为每次合并的时候复杂度\(O(4 ^ 3)\),所以总复杂度 \(O(64NlogN)\)

Code

实现下来用的是 Fhq-Treap

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std; const int N = 1e5 + 10; typedef long long LL; int n, idx, rt;
LL last = 0; struct F{
LL w[4][4];
F(){}
F (int a, int b, int c, int v) {
memset(w, 0, sizeof w);
w[0][0] = w[3][3] = (LL)a * v, w[1][1] = (LL)b * v, w[2][2] = (LL)c * v;
for (int i = 0; i < 4; i++)
for (int j = i + 1; j < 4; j++) w[i][j] = max(w[i][j - 1], w[j][j]);
}
F operator + (const F &b) const {
F c; memset(c.w, 0, sizeof c.w);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
for (int k = i; k <= j; k++) c.w[i][j] = max(c.w[i][j], w[i][k] + b.w[k][j]);
return c;
}
} val[N << 2], sum[N << 2]; struct T{
int l, r, rnd, sz, len, a, b, c;
LL tot;
} t[N << 2]; int getNode(int a, int b, int c, int len) {
t[++idx] = (T) { 0, 0, rand(), 1, len, a, b, c, len};
val[idx] = sum[idx] = F(a, b, c, len);
return idx;
} void pushup(int p) {
t[p].sz = t[t[p].l].sz + t[t[p].r].sz + 1;
t[p].tot = t[t[p].l].tot + t[t[p].r].tot + t[p].len;
sum[p] = val[p];
if (t[p].l) sum[p] = sum[t[p].l] + sum[p];
if (t[p].r) sum[p] = sum[p] + sum[t[p].r];
} int merge(int A, int B) {
if (!A || !B) return A + B;
if (t[A].rnd < t[B].rnd) {
t[A].r = merge(t[A].r, B);
pushup(A);
return A;
} else {
t[B].l = merge(A, t[B].l);
pushup(B);
return B;
}
} // 按 tot 的 size 分裂,让 x 的 tot 总和 <= k
void split1(int p, LL k, int &x, int &y) {
if (!p) { x = y = 0; return; }
if (t[t[p].l].tot + t[p].len <= k) {
x = p;
split1(t[p].r, k - (t[t[p].l].tot + t[p].len), t[p].r, y);
} else {
y = p;
split1(t[p].l, k, x, t[p].l);
}
pushup(p);
} // 按 size 分裂,让 x 的 sz 总和 <= k
void split2(int p, int k, int &x, int &y) {
if (!p) { x = y = 0; return; }
if (t[t[p].l].sz + 1 <= k) {
x = p;
split2(t[p].r, k - (t[t[p].l].sz + 1), t[p].r, y);
} else {
y = p;
split2(t[p].l, k, x, t[p].l);
}
pushup(p);
} int main() {
int x, y, z;
scanf("%d", &n);
while (n--) {
LL p; int a, b, c, v; scanf("%lld%d%d%d%d", &p, &a, &b, &c, &v);
split1(rt, p, x, y); split2(y, 1, y, z);
int w = getNode(a, b, c, v), l = p - t[x].tot;
if (l) t[w].l = getNode(t[y].a, t[y].b, t[y].c, l);
if (t[y].len - l) t[w].r = getNode(t[y].a, t[y].b, t[y].c, t[y].len - l);
pushup(w);
rt = merge(x, merge(w, z));
printf("%lld\n", sum[rt].w[0][3] - last);
last = sum[rt].w[0][3];
}
return 0;
}

BJOI2017 喷式水战改的更多相关文章

  1. [bzoj4906][BeiJing2017]喷式水战改

    来自FallDream的博客,未经允许,请勿转载,谢谢. [题目背景] 拿到了飞机的驾照(?),这样补给就不愁了 XXXX年XX月XX日 拿到了喷气机(??)的驾照,这样就飞得更快了 XXXX年XX月 ...

  2. [BJOI2017]魔法咒语 --- AC自动机 + 矩阵优化

    bzoj 4860   LOJ2180   洛谷P3175 [BJOI2017]魔法咒语 题目描述: Chandra 是一个魔法天才. 从一岁时接受火之教会洗礼之后,Chandra 就显示出对火元素无 ...

  3. 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  4. Linux.NET实战手记—自己动手改泥鳅(上)

    各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...

  5. Linux.NET实战手记—自己动手改泥鳅(下)

    在上回合中,我们不痛不痒的把小泥鳅的数据库从只能供在Windows下运行的Access数据库改为支持跨平台的MYSQL数据库,毫无营养的修改,本回合中,我们将把我们修改后得来的项目往Linux中部署. ...

  6. Android 打开方式选定后默认了改不回来?解决方法(三星s7为例)

    Android 打开方式选定后默认了改不回来?解决方法(三星s7为例) 刚刚在测试东西,打开一个gif图,然后我故意选择用支付宝打开,然后...支付宝当然不支持,我觉得第二次打开它应该还会问我,没想到 ...

  7. 把PDF的底色改成护眼色,这样读起文章来就不是很累了······

    PDF格式背景改变方法如下: 打开PDF 点击 编辑 ->首选项->辅助工具->选中"替换文档颜色"和" 自定义颜色"->将背景颜色改成 ...

  8. 3.EF 6.0 Code-First实现增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-entity-framework-5-0-code- ...

  9. 4.在MVC中使用仓储模式进行增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-using-the-repository-pattern-in-mvc/ 系列目录: ...

随机推荐

  1. IDEA “Cannot resolve symbol” 解决办法

    IDEA 无法识别同一个 package 里的其他类,将其显示为红色,但是 compile 没有问题.鼠标放上去后显示 "Cannot resolve symbol XXX",重启 ...

  2. impala语句

    0.保留两位小数 round(字段a, 需要保留几位小数) round( data, 4) 1. case wen case when 字段a = '01' and 字段b = '01' and 字段 ...

  3. B+树作为数据库索引有什么优势?I/O方面?

    首先要了解磁盘预读机制,大致就是说,从磁盘读取数据的速度比从内存读取数据的速度要慢很多,所以要尽量减少磁盘I/O的操作,尽量增加内存I/O操作,既然这样,我们可以从磁盘提前把需要的数据拿到内存,这样需 ...

  4. 教你用Camtasia制作精美片头

    大家都知道在视频播放中,如果有一个令人印象深刻的精彩开头,整个视频的内容都能因此得到不少升华.所以有一个好的片头对于视频的制作来说十分重要.今天我们就来讲一下用Camtasia制作片头的方法. 首先, ...

  5. guitar pro 系列教程(十八):Guitar Pro怎么设置吉他谱的局部速度?

    关于Guitar Pro的使用功能我们在前面的文章也有讲了不少,对于新手的小伙伴,就小编个人而言,在吉他编曲,演绎方面遇到的困难不是一点两点,我们只有通过学习了解他的全部,才能在以后的吉他创作中得心印 ...

  6. 小程序ui自动化(一),用uiAutormatorViewer定位元素失败,如何解决

    1.定位元素 用android ADT自带工具:uiAutormatorViewer,会报如下错误 可能是环境与手机不兼容 可以用以下方法解决:(参考:https://blog.csdn.net/qq ...

  7. MySQL开发篇(未完待续)

    一.索引 什么是索引? 索引是帮助Mysql提高获取数据的数据结构,换一句话讲就是"排好序的快速查找的数据结构". 1.索引的分类 MySQL主要的几种索引类型:1.普通索引.2. ...

  8. [poi使用]使用excel模版导出excel

    ​ Apache POI是基于Office Open XML标准(OOXML)和Microsoft的OLE 2复合文档格式(OLE2)处理各种文件格式的开源项目.简而言之,您可以使用Java读写MS ...

  9. pytest测试框架入门

    安装pytest 命令行输入: pip install -U pytest 检查是否安装了正确的版本: λ pytest --version This is pytest version 5.3.5, ...

  10. mybatis 动态SQL 源码解析

    摘要 mybatis是个人最新喜欢的半自动ORM框架,它实现了SQL和业务逻辑的完美分割,今天我们来讨论一个问题,mybatis 是如何动态生成SQL SqlSessionManager sqlSes ...