动态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. 牛客网:Java重命名文件

    项目介绍 不管是C/C++还是JAVA,都可能生成一些持久性数据,我们可以将数据存储在文件或数据库中,此项目主要训练学习Java对本地磁盘的文件重命名,例如C:\nowcoder.txt重命名C:\n ...

  2. anaconda --包管理和环境管理器

    前言: 以下所有的命令都Win10环境的 Anaconda Prompt 中 环境管理 创建虚拟环境 conda create --name env_name python 也可以指定 Python ...

  3. SQLServer无法删除登录名'***',因为该用户当前正处于登录状态解决方法

    问题描述: sqlserver在删除登录名的时候提示删除失败 标题: Microsoft SQL Server Management Studio -------------------------- ...

  4. 【任务】Python语言程序设计.MOOC学习

    [博客导航] [Python导航] 任务 18年11月29日开始,通过9周时间跨度,投入约50小时时间,在19年1月25日之前,完成中国大学MOOC平台上的<Python语言程序设计>课程 ...

  5. const int *p;int *const p;区别及用法

    在单片机程序设计中,我们经常会用到const这个关键字,在有些单片机的编译器中可能会是code(比如51系列单片机),但我们在学习C语言的时候,首先还是先学到的const.我们知道,const关键字的 ...

  6. solr 7.7 搭建和搜索

    最近做了个solr搜索的demo, 用的是solr7.7,之前网上好多文章搭建solr都是5.5+tomcat.. 自己摆弄了下,发现solr7.7和5.5 的部分文件夹有些改动,没有深究原理也就没有 ...

  7. Putty中的pscp和psftp的简明用法

    用习惯了putty,那是真心的方便啊,putty文件夹下其他的小兄弟也不能忽略啊. 以前的时候,从远程服务器下载个文件用winscp,后来,发现在putty文件夹里好像有一个 pscp和psftp,今 ...

  8. parquet文件 读取 原理

    学习一下parquet存储结构 原理 以及使用

  9. [LeetCode] 12,13 整数和罗马数互转

    12. 整数转罗马数字 题目链接:https://leetcode-cn.com/problems/integer-to-roman/ 题目描述: 罗马数字包含以下七种字符: I, V, X, L,C ...

  10. 012_call和apply区别

    一. function fn(a,b) { console.log(this); } fn.call(null,1,2); //call为参数方式 fn.apply(null,[1,2]); //ap ...