动态DP其实挺简单一个东西。

把DP值的定义改成去掉重儿子之后的DP值。

重链上的答案就用线段树/lct维护,维护子段/矩阵都可以。其实本质上差不多...

修改的时候在log个线段树上修改。轻儿子所在重链的线段树的根拿去更新父亲的DP值。

 #include <cstdio>
#include <algorithm> const int N = , INF = 0x3f3f3f3f; template <class T> inline void read(T &x) {
x = ;
char c = getchar();
bool f = ;
while(c < '' || c > '') {
if(c == '-') {
f = ;
}
c = getchar();
}
while(c >= '' && c <= '') {
x = (x << ) + (x << ) + c - ;
c = getchar();
}
if(f) {
x = (~x) + ;
}
return;
} struct Edge {
int nex, v;
}edge[N << ]; int tp; // 0 0 0
// 1 0 1
// 2 1 0
// 3 1 1 int top[N], e[N], siz[N], pos[N], id[N], val[N], fa[N], son[N], d[N], num, n, len[N];
int f[N][], seg[N * ][], tot, ls[N * ], rs[N * ], rt[N]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void DFS_1(int x, int f) { // son siz fa d
fa[x] = f;
d[x] = d[f] + ;
siz[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) {
continue;
}
DFS_1(y, x);
siz[x] += siz[y];
if(siz[y] > siz[son[x]]) {
son[x] = y;
}
}
return;
} void DFS_2(int x, int f) { // pos id top
top[x] = f;
pos[x] = ++num;
id[num] = x;
len[x] = ;
if(son[x]) {
DFS_2(son[x], f);
len[x] = len[son[x]] + ;
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == son[x] || y == fa[x]) {
continue;
}
DFS_2(y, y);
}
return;
} inline void pushup(int o) {
int l = ls[o], r = rs[o];
seg[o][] = std::max(seg[l][] + seg[r][], seg[l][] + seg[r][]);
seg[o][] = std::max(seg[o][], seg[l][] + seg[r][]); seg[o][] = std::max(seg[l][] + seg[r][], seg[l][] + seg[r][]);
seg[o][] = std::max(seg[o][], seg[l][] + seg[r][]); seg[o][] = std::max(seg[l][] + seg[r][], seg[l][] + seg[r][]);
seg[o][] = std::max(seg[o][], seg[l][] + seg[r][]); seg[o][] = std::max(seg[l][] + seg[r][], seg[l][] + seg[r][]);
seg[o][] = std::max(seg[o][], seg[l][] + seg[r][]);
return;
} inline void build(int l, int r, int &o) {
if(!o) {
o = ++tot;
}
if(l == r) {
seg[o][] = f[id[r]][];
seg[o][] = -INF;
seg[o][] = -INF;
seg[o][] = val[id[r]] + f[id[r]][];
return;
}
int mid = (l + r) >> ;
build(l, mid, ls[o]);
build(mid + , r, rs[o]);
pushup(o);
return;
} void change(int p, int l, int r, int o) {
//printf("change -- : %d %d %d \n", p, l, r);
if(l == r) {
seg[o][] = f[id[r]][];
seg[o][] = -INF;
seg[o][] = -INF;
seg[o][] = val[id[r]] + f[id[r]][];
//printf("%d = %d + %d \n", id[r], val[id[r]], f[id[r]][1]);
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
change(p, l, mid, ls[o]);
}
else {
change(p, mid + , r, rs[o]);
}
pushup(o);
//printf("%d %d \n", id[l], id[r]);
//printf("%d %d %d %d \n", seg[o][0], seg[o][1], seg[o][2], seg[o][3]);
return;
} inline void change(int x, int v) {
//printf("change %d %d \n", x, v);
val[x] = v;
while(x) {
int xx = top[x];
if(fa[xx]) {
int temp = std::max(seg[rt[xx]][], seg[rt[xx]][]);
f[fa[xx]][] -= temp;
f[fa[xx]][] -= std::max(std::max(seg[rt[xx]][], seg[rt[xx]][]), temp);
}
//printf("ch %d %d %d \n", x, xx, id[pos[xx] + len[xx] - 1]);
change(pos[x], pos[xx], pos[xx] + len[xx] - , rt[xx]);
if(fa[xx]) {
int temp = std::max(seg[rt[xx]][], seg[rt[xx]][]);
f[fa[xx]][] += temp;
f[fa[xx]][] += std::max(std::max(seg[rt[xx]][], seg[rt[xx]][]), temp);
}
x = fa[xx];
}
return;
} int main() {
int m;
read(n); read(m);
for(int i = ; i <= n; i++) {
read(val[i]);
}
for(int i = , x, y; i < n; i++) {
read(x); read(y);
add(x, y);
add(y, x);
}
DFS_1(, );
DFS_2(, );
for(int i = ; i <= n; i++) {
int x = id[n + - i];
if(top[x] == x) {
build(pos[x], pos[x] + len[x] - , rt[x]);
if(fa[x]) {
int temp = std::max(seg[rt[x]][], seg[rt[x]][]);
f[fa[x]][] += temp;
f[fa[x]][] += std::max(std::max(seg[rt[x]][], seg[rt[x]][]), temp);
}
}
} for(int i = , x, y; i <= m; i++) {
read(x); read(y);
change(x, y);
int a = std::max(seg[rt[]][], seg[rt[]][]);
int b = std::max(seg[rt[]][], seg[rt[]][]);
printf("%d\n", std::max(a, b));
} return ;
}

AC代码

还有noip最后一题,虽然正解是倍增DP但是显然写动态DP啊...

注意树剖和线段树别写错了..没开O2少用std的函数

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath> typedef long long LL;
const int N = ;
const LL INF = 1e17; template <class T> inline void read(T &x) {
x = ;
char c = getchar();
while(c < '' || c > '') {
c = getchar();
}
while(c >= '' && c <= '') {
x = (x << ) + (x << ) + c - ;
c = getchar();
}
return;
} struct Edge {
int nex, v;
}edge[N * ]; int tp; LL val[N], f[N * ][][], Val[N][];
int e[N], n, m;
int fa[N], top[N], pos[N], id[N], siz[N], son[N], num, d[N], ed[N]; // tree div
int tot, ls[N * ], rs[N * ], rt[N]; // segment tree
char str[]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void DFS_1(int x, int f) { // fa son siz d
fa[x] = f;
siz[x] = ;
d[x] = d[f] + ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) {
continue;
}
DFS_1(y, x);
siz[x] += siz[y];
if(siz[y] > siz[son[x]]) {
son[x] = y;
}
}
//printf("son %d = %d \n", x, son[x]);
//printf("siz %d = %d \n", x, siz[x]);
return;
} void DFS_2(int x, int f) { // top pos id
pos[x] = ++num;
top[x] = f;
id[num] = x;
ed[f] = num;
//printf("x = %d ed %d = %d \n", x, f, ed[f]);
if(son[x]) {
DFS_2(son[x], f);
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == fa[x] || y == son[x]) {
continue;
}
DFS_2(y, y);
}
return;
} inline LL mymin(LL x, LL y) {
return x < y ? x : y;
} inline void exmin(LL &a, LL b) {
a > b ? a = b : ;
return;
} inline void pushup(int o) {
int l = ls[o], r = rs[o];
f[o][][] = INF;
exmin(f[o][][], f[l][][] + f[r][][]);
exmin(f[o][][], f[l][][] + f[r][][]);
exmin(f[o][][], f[l][][] + f[r][][]);
f[o][][] = INF;
exmin(f[o][][], f[l][][] + f[r][][]);
exmin(f[o][][], f[l][][] + f[r][][]);
exmin(f[o][][], f[l][][] + f[r][][]);
f[o][][] = INF;
exmin(f[o][][], f[l][][] + f[r][][]);
exmin(f[o][][], f[l][][] + f[r][][]);
exmin(f[o][][], f[l][][] + f[r][][]);
f[o][][] = INF;
exmin(f[o][][], f[l][][] + f[r][][]);
exmin(f[o][][], f[l][][] + f[r][][]);
exmin(f[o][][], f[l][][] + f[r][][]);
return;
} void build(int l, int r, int &o) {
if(!o) {
o = ++tot;
}
if(l == r) {
// init
int x = id[r];
f[o][][] = Val[x][];
f[o][][] = INF;
f[o][][] = INF;
f[o][][] = val[x] + Val[x][];
return;
}
int mid = (l + r) >> ;
build(l, mid, ls[o]);
build(mid + , r, rs[o]);
pushup(o);
return;
} inline int lca(int x, int y) {
while(top[x] != top[y]) {
if(d[top[x]] <= d[top[y]]) {
y = fa[top[y]];
}
else {
x = fa[top[x]];
}
}
return (d[x] < d[y]) ? x : y;
} inline bool link(int x, int y) {
int z = lca(x, y);
return std::abs(d[x] - d[y]) == && (z == x || z == y);
} inline void change(int p, int v, int l, int r, int o) {
//printf("change %d %d %d %d \n", p, v, l, r);
if(l == r) {
if(v) {
f[o][][] = INF;
}
else {
f[o][][] = INF;
}
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
change(p, v, l, mid, ls[o]);
}
else {
change(p, v, mid + , r, rs[o]);
}
pushup(o);
return;
} inline void update(int p, int l, int r, int o) {
if(l == r) {
int x = id[r];
f[o][][] = Val[x][];
f[o][][] = val[x] + Val[x][];
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
update(p, l, mid, ls[o]);
}
else {
update(p, mid + , r, rs[o]);
}
pushup(o);
return;
} inline void change(int x, int a) {
int xx = x;
while(x) {
if(fa[top[x]]) {
LL temp = mymin(f[rt[top[x]]][][], f[rt[top[x]]][][]);
Val[fa[top[x]]][] -= temp;
Val[fa[top[x]]][] -= mymin(mymin(f[rt[top[x]]][][], f[rt[top[x]]][][]), temp);
}
if(x != xx)
update(pos[x], pos[top[x]], ed[top[x]], rt[top[x]]);
else
change(pos[x], a, pos[top[x]], ed[top[x]], rt[top[x]]);
if(fa[top[x]]) {
LL temp = mymin(f[rt[top[x]]][][], f[rt[top[x]]][][]);
Val[fa[top[x]]][] += temp;
Val[fa[top[x]]][] += mymin(mymin(f[rt[top[x]]][][], f[rt[top[x]]][][]), temp);
}
x = fa[top[x]];
}
return;
} inline void recover(int x) {
while(x) {
if(fa[top[x]]) {
LL temp = mymin(f[rt[top[x]]][][], f[rt[top[x]]][][]);
Val[fa[top[x]]][] -= temp;
Val[fa[top[x]]][] -= mymin(mymin(f[rt[top[x]]][][], f[rt[top[x]]][][]), temp);
}
update(pos[x], pos[top[x]], ed[top[x]], rt[top[x]]);
if(fa[top[x]]) {
LL temp = mymin(f[rt[top[x]]][][], f[rt[top[x]]][][]);
Val[fa[top[x]]][] += temp;
Val[fa[top[x]]][] += mymin(mymin(f[rt[top[x]]][][], f[rt[top[x]]][][]), temp);
}
x = fa[top[x]];
}
return;
} int main() { //freopen("in.in", "r", stdin);
//freopen("my.out", "w", stdout);
read(n); read(m);
scanf("%s", str);
for(register int i = ; i <= n; i++) {
read(val[i]);
}
for(register int i = , x, y; i < n; i++) {
read(x); read(y);
add(x, y); add(y, x);
}
// prework
DFS_1(, );
DFS_2(, );
// build
for(register int a = n; a >= ; a--) {
int x = id[a];
if(top[x] == x) {
build(pos[x], ed[x], rt[x]);
if(fa[x]) {
int father = fa[x];
LL temp = mymin(f[rt[x]][][], f[rt[x]][][]);
Val[father][] += temp;
Val[father][] += mymin(mymin(f[rt[x]][][], f[rt[x]][][]), temp);
}
}
} for(register int i = , x, a, y, b; i <= m; i++) {
scanf("%d%d%d%d", &x, &a, &y, &b);
if(!a && !b && link(x, y)) {
puts("-1");
continue;
}
change(x, a);
change(y, b);
printf("%lld\n", mymin(mymin(f[rt[]][][], f[rt[]][][]), mymin(f[rt[]][][], f[rt[]][][])));
recover(x);
recover(y);
} return ;
}

AC代码

洛谷P4719 动态dp的更多相关文章

  1. 洛谷P4719 动态DP —— 动态DP(树剖+矩乘)

    题目:https://www.luogu.org/problemnew/show/P4719 感觉这篇博客写得挺好:https://blog.csdn.net/litble/article/detai ...

  2. 洛谷P4719 【模板】动态dp(ddp LCT)

    题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...

  3. 洛谷 P4719 【模板】动态dp【动态dp】

    是动态dp的板子 大致思想就是用g[u]来表示不包含重链转移的dp值,然后用线段树维护重链,这样线段树的根就相当于这条重链的top的真实dp值 每次修改的时候,修改x点会影响到x到根的真实dp值,但是 ...

  4. 洛谷P4719 【模板】"动态 DP"&动态树分治

    [模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...

  5. 洛谷教主花园dp

    洛谷-教主的花园-动态规划   题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价 ...

  6. 洛谷P1393 动态逆序对(CDQ分治)

    传送门 题解 听别人说这是洛谷用户的双倍经验啊……然而根本没有感觉到……因为另外的那题我是用树状数组套主席树做的……而且莫名其妙感觉那种方法思路更清晰(虽然码量稍稍大了那么一点点)……感谢Candy大 ...

  7. 洛谷 p6858 深海少女与胖头鱼 洛谷月赛 期望dp

    洛谷10月月赛 2 t2 深海少女与胖头鱼 题目链接 参考资料:洛谷10月赛2讲评ppt; 本篇题解考完那天就开始写,断断续续写到今天才写完 本题作为基础的期望dp题,用来学习期望dp还是很不错的 ( ...

  8. 洛谷P4719 【模板】动态dp

    https://www.luogu.org/problemnew/show/P4719 大概就是一条链一条链的处理(“链”在这里指重链),对于每一条链,对于其上每一个点,先算出它自身和所有轻儿子的贡献 ...

  9. 2019.01.04 洛谷P4719 【模板】动态dp(链分治+ddp)

    传送门 ddpddpddp模板题. 题意简述:给你一棵树,支持修改一个点,维护整棵树的最大带权独立集. 思路: 我们考虑如果没有修改怎么做. 貌似就是一个sbsbsb树形dpdpdp,fi,0f_{i ...

随机推荐

  1. mysql备份与还原!

    一.备份常用操作基本命令 1.备份命令mysqldump格式 格式:mysqldump -h主机名  -P端口 -u用户名 -p密码 –database 数据库名 > 文件名.sql 2.备份M ...

  2. USB初学(一)---USB-HID的初步认识【转】

    HID是一种USB通信协议,无需安装驱动就能进行交互,在学习HID之前,先来复习一下USB协议的相关内容. USB设备描述符-概述 当插入USB设备后,主机会向设备请求各种描述符来识别设备.那什么是设 ...

  3. typora快捷键

    目录 基础信息 常用快捷键 修改快捷键 基础信息 typora是一款极佳的markdown写作软件,编辑和预览两者合二为一,免费良心软件,推荐使用. 官网:https://www.typora.io/ ...

  4. java每日一总结

    一, 1.安装jdk时路径中不能有空格或者中文. 二, 1.进入文件夹:cd+文件夹名称. 2.进入多级文件夹:cd+文件夹1\文件夹2\文件夹3. 3.返回上一级:cd 空格+... 4.返回根路径 ...

  5. CSS---选择器种类 | 层叠性权重

    一.css选择器种类 1.1,ID选择器 1.2,类选择器 1.3,标签选择器 1.4,后代选择器 1.5,子代选择器 1.6,交集选择器 1.7,并集选择器 1.8,通配符选择器 1.9,属性选择器 ...

  6. Koa 中 ejs 模板的使用

    ejs的基本使用 安装 koa-views 和 ejs npm install --save koa-views/cnpm install --save koa-views npm install e ...

  7. [LeetCode]2. 两数相加

    题目链接:https://leetcode-cn.com/problems/add-two-numbers/ 题目描述: 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 ...

  8. Linux 实例常用内核网络参数介绍与常见问题处理

    本文总结了常见的 Linux 内核参数及相关问题.修改内核参数前,您需要: 从实际需要出发,最好有相关数据的支撑,不建议随意调整内核参数. 了解参数的具体作用,且注意同类型或版本环境的内核参数可能有所 ...

  9. Java项目的导入和导出

    在很多情况下,需要将当前的 Java工程传递给其他人继续工作, 或协同工作,或者是从其他人那里接收到传递来的Java项目, 就需要掌握 Java项目的导入和导出. 以 Hello World 为例: ...

  10. 性能测试监控平台:InfluxDB+Grafana+Jmeter

    前面的博客介绍了InfluxDB.Telegraf.Grafana的安装和使用方法,这篇博客,介绍下如何利用这些开源工具搭建性能测试监控平台... 前言 性能测试工具jmeter自带的监视器对性能测试 ...