BJOI2017 喷式水战改
题目链接。
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 喷式水战改的更多相关文章
- [bzoj4906][BeiJing2017]喷式水战改
来自FallDream的博客,未经允许,请勿转载,谢谢. [题目背景] 拿到了飞机的驾照(?),这样补给就不愁了 XXXX年XX月XX日 拿到了喷气机(??)的驾照,这样就飞得更快了 XXXX年XX月 ...
- [BJOI2017]魔法咒语 --- AC自动机 + 矩阵优化
bzoj 4860 LOJ2180 洛谷P3175 [BJOI2017]魔法咒语 题目描述: Chandra 是一个魔法天才. 从一岁时接受火之教会洗礼之后,Chandra 就显示出对火元素无 ...
- 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...
- Linux.NET实战手记—自己动手改泥鳅(上)
各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...
- Linux.NET实战手记—自己动手改泥鳅(下)
在上回合中,我们不痛不痒的把小泥鳅的数据库从只能供在Windows下运行的Access数据库改为支持跨平台的MYSQL数据库,毫无营养的修改,本回合中,我们将把我们修改后得来的项目往Linux中部署. ...
- Android 打开方式选定后默认了改不回来?解决方法(三星s7为例)
Android 打开方式选定后默认了改不回来?解决方法(三星s7为例) 刚刚在测试东西,打开一个gif图,然后我故意选择用支付宝打开,然后...支付宝当然不支持,我觉得第二次打开它应该还会问我,没想到 ...
- 把PDF的底色改成护眼色,这样读起文章来就不是很累了······
PDF格式背景改变方法如下: 打开PDF 点击 编辑 ->首选项->辅助工具->选中"替换文档颜色"和" 自定义颜色"->将背景颜色改成 ...
- 3.EF 6.0 Code-First实现增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-entity-framework-5-0-code- ...
- 4.在MVC中使用仓储模式进行增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-using-the-repository-pattern-in-mvc/ 系列目录: ...
随机推荐
- python之路《八》装饰器
装饰器是个好东西啊 那么装饰器是个什么样的东西呢,他又能做些什么呢? 1.为什么装饰器 当我们一个程序已经构建完成,并且已经发布出去了,但是现在需要增加一个活动,例如淘宝给你发送一个今日优惠,或者开启 ...
- a标签禁用
a标签禁用可以使用CSS3的特性来控制 <a class="disabled">我是a标签</a> a.disabled { pointer-events: ...
- wireshark分析nmap和metasploit内置的syn扫描
syn扫描 syn扫描,根据三次握手,向端口发送syn包,如果对方回应SYN/ACK,则证明端口开放 首先是nmap 速度很快,0.67秒完成,看下wireshark的抓取 一次发送了大量的syn包 ...
- 几分钟看懂EasyRecovery数据恢复原理,比我想象的简单易懂得多
可能很多人知道使用数据恢复软件EasyRecovery可以恢复丢失的数据,但是却不知道它是什么原理.现在我们就以硬盘数据恢复为例,一起来了解下EasyRecovery数据恢复原理. 当硬盘数据丢失后, ...
- python中操作excel数据
python操作excel,python有提供库 本文介绍openpyxl,他只支持新型的excell( xlsx)格式,读取速度还可以 1.安装 pip install openpyxl 2.使用 ...
- web自动化测试难点 滚动条操作、日期框处理、上传文件
如何把页面滑到最低部? 一般来说,做web自动化测试时,不需要单独写代码,把页面滑到可见,因为click操作,只要是元素存在并且加载出来了,就可以点击到,无需另外写滑动元素的代码. 如果特殊情况需要滑 ...
- Elasticsearch 理解mapping中的store属性
默认情况下,对字段值进行索引以使其可搜索,但不存储它们 (store). 这意味着可以查询该字段,但是无法检索原始字段值.在这里我们必须理解的一点是: 如果一个字段的mapping中含有store属性 ...
- DNS系列—DNS简介
DNS是什么? 如果了解互联网主机之间是用IP地址来进行通信的话,有了这个认识的前提,我们来聊一下什么是DNS.一个IP地址有十几个字符那么长,和手机号码长度差不多,我们怎么记住这些我们想要访问的主机 ...
- python接口测试2-开发WEB接口
首先要安装flask包: pip install flask 开发一个简单的API接口 # 1. 导入包 from flask import Flask, request # 2. 实例化一个 app ...
- 【电子取证:FTK Imager篇】DD、E01系统镜像仿真
星河滚烫,人生有理想! ---[suy999] DD.E01系统镜像动态仿真 (一)使用到的软件 1.FTK Imager (v4.5.0.3) 2.VMware Workstation 15 P ...