题解

在冬令营上听到冬眠的东西,现在都是板子了猫锟真的是好毒瘤啊(雾)

(立个flag,我去thusc之前要把WC2018T1乱搞过去= =)

好的,我们可以参考猫锟的动态动态dp的课件,然后你发现你什么都看不懂(菜啊

但是我们仔细看一看,可以发现用数据结构维护矩阵,那么我们尝试构造一个矩阵

\(\begin{bmatrix} \ g_{u,0} & g_{u,0}\\ g_{u,1} & 0 \end{bmatrix} \begin{bmatrix} f_{son[u],0}\\ f_{son[u],1} \end{bmatrix} = \begin{bmatrix} f_{u,0}\\ f_{u,1} \end{bmatrix}\)
其中\(g_{u,0}\)表示不选u,对于u的子树,除了u的重儿子所在子树,u的轻儿子最大独立集是多少
\(g_{u,1}\)表示选了u
\(f_{u,0}\)表示不选u,以u为根的子树最大独立集是多少
\(f_{u,1}\)表示选了u,以u为根的子树最大独立集是多少

这个矩阵的运算不是加法和乘法,而是加法和取max
也就是\(c_{i,j} = max(a_{i,k} + b_{k,j})\)
也是满足结合律的

这样我们就可以用一个树链剖分来维护这些矩阵了

注意一下,合并矩阵的时候是左右合并,但是乘法的时候一定先从右边乘
举个例子,我们的运算实际是这样的
一条链:
3 - 4 - 5
3是4的父亲,4是5的父亲
\(\begin{bmatrix} \ g_{3,0} & g_{3,0}\\ g_{3,1} & 0 \end{bmatrix} \begin{bmatrix} \ g_{4,0} & g_{4,0}\\ g_{4,1} & 0 \end{bmatrix} \begin{bmatrix} f_{5,0}\\ f_{5,1} \end{bmatrix} = \begin{bmatrix} f_{3,0}\\ f_{3,1} \end{bmatrix}\)
也就是5先和4的矩阵结合,再和3的矩阵结合

实际上写代码的时候,既然每一条链的最后一定是一个叶子节点,我们就可以直接把f0设成0,f1设成0去做矩阵乘法,乘上这条链上所有的矩阵作为链顶的f值

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
//#define ivorysi
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define mo 974711
#define RG register
#define MAXN 100005
#define debug
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {res = 0;char c = getchar();T f = 1;while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {res = res * 10 + c - '0';c = getchar();}res *= f;
}
template<class T>
void out(T x) {if(x < 0) putchar('-'),x = -x;if(x >= 10) out(x / 10);putchar('0' + x % 10);
}
const int MOD = 1000000007;
int mul(int a,int b) {return 1LL * a * b % MOD;
}
int inc(int a,int b) {a = a + b;if(a >= MOD) a -= MOD;return a;
}int fpow(int x,int c) {int res = 1,t = x % MOD;while(c) {if(c & 1) res = mul(res,t);t = mul(t,t);c >>= 1;}return res;
}
int N,Q;
int64 val[MAXN],g[MAXN][2],f[MAXN][2];
int top[MAXN],btm[MAXN],dfn[MAXN],fa[MAXN],dep[MAXN],son[MAXN],idx,siz[MAXN],L[MAXN],pos[MAXN];
int cnt = 0;
struct node {int to,next;
}E[MAXN * 2];
int head[MAXN],sumE;
struct tr_node {int l,r;int64 M[2][2];
}tr[MAXN * 4];
void add(int u,int v) {E[++sumE].to = v;E[sumE].next = head[u];head[u] = sumE;
}
void dfs1(int u) {dep[u] = dep[fa[u]] + 1;siz[u] = 1;for(int i = head[u] ; i ; i = E[i].next) {int v = E[i].to;if(v != fa[u]) {fa[v] = u;dfs1(v);siz[u] += siz[v];if(siz[v] > siz[son[u]]) son[u] = v;}}
}
void dfs2(int u) {dfn[u] = ++idx;L[idx] = u;if(!top[u]) {top[u] = u;}if(son[u]) {top[son[u]] = top[u];dfs2(son[u]);btm[u] = btm[son[u]]; }g[u][1] = val[u];g[u][0] = 0;for(int i = head[u] ; i ; i = E[i].next) {int v = E[i].to;if(v != son[u] && v != fa[u]) {dfs2(v);g[u][0] += max(f[v][0],f[v][1]);g[u][1] += max(0LL,f[v][0]);}}f[u][1] = g[u][1] + max(f[son[u]][0],0LL);f[u][0] = g[u][0] + max(f[son[u]][1],f[son[u]][0]);if(!son[u]) btm[u] = u;
}
void update(int u) {int L = u << 1,R = u << 1 | 1;tr[u].M[0][0] = max(tr[L].M[0][0] + tr[R].M[0][0],tr[L].M[0][1] + tr[R].M[1][0]);tr[u].M[0][1] = max(tr[L].M[0][0] + tr[R].M[0][1],tr[L].M[0][1] + tr[R].M[1][1]);tr[u].M[1][0] = max(tr[L].M[1][0] + tr[R].M[0][0],tr[L].M[1][1] + tr[R].M[1][0]);tr[u].M[1][1] = max(tr[L].M[1][0] + tr[R].M[0][1],tr[L].M[1][1] + tr[R].M[1][1]);
}
void build(int u,int l,int r) {tr[u].l = l;tr[u].r = r;if(l == r) {int v = L[l];tr[u].M[0][0] = g[v][0];tr[u].M[0][1] = g[v][0];tr[u].M[1][0] = g[v][1];tr[u].M[1][1] = 0;pos[v] = u;return ;}int mid = (l + r) >> 1;build(u << 1,l,mid);build(u << 1 | 1,mid + 1,r);update(u);
}
void Query(int u,int L,int R,int64 &f0,int64 &f1) {if(tr[u].l == L && tr[u].r == R) {int64 x = max(f0 + tr[u].M[0][0],f1 + tr[u].M[0][1]);int64 y = max(f0 + tr[u].M[1][0],f1 + tr[u].M[1][1]);f0 = x;f1 = y;return;}int mid = (tr[u].l + tr[u].r) >> 1;if(R <= mid) Query(u << 1,L,R,f0,f1);else if(L > mid) Query(u << 1 | 1,L,R,f0,f1);else {Query(u << 1 | 1,mid + 1,R,f0,f1);Query(u << 1,L,mid,f0,f1);}
}
void Change(int x) {int t = pos[x] >> 1;while(t) {update(t);t >>= 1;}
}
void Change_tr(int x) {while(1) {int a = top[x];if(fa[a] != 0) {g[fa[a]][0] -= max(f[a][0],f[a][1]);g[fa[a]][1] -= max(f[a][0],0LL);}f[a][0] = 0;f[a][1] = 0;Query(1,dfn[top[x]],dfn[btm[x]],f[a][0],f[a][1]);if(fa[a] == 0) break;g[fa[a]][0] += max(f[a][0],f[a][1]);g[fa[a]][1] += max(f[a][0],0LL);x = fa[a];tr[pos[x]].M[0][0] = tr[pos[x]].M[0][1] = g[x][0];tr[pos[x]].M[1][0] = g[x][1];tr[pos[x]].M[1][1] = 0;Change(x);}
}
void Init() {read(N);read(Q);for(int i = 1 ; i <= N ; ++i) read(val[i]);int u,v;for(int i = 1 ; i < N ; ++i) {read(u);read(v);add(u,v);add(v,u);}dfs1(1);dfs2(1);build(1,1,N);
}
void Solve() {int x;int64 y;while(Q--) {++cnt;read(x);read(y);g[x][1] = g[x][1] - val[x] + y;tr[pos[x]].M[1][0] = g[x][1];val[x] = y;Change(x);Change_tr(x);out(max(f[1][0],f[1][1]));enter;}
}
int main() {
#ifdef ivorysifreopen("f1.in","r",stdin);
#endifInit();Solve();return 0;
}

转载于:https://www.cnblogs.com/ivorysi/p/9118007.html

【洛谷】P4643 【模板】动态dp相关推荐

  1. 【洛谷P4719】动态DP【LCT】【矩阵】

    之前的后缀平衡树其实没完,只是过于鬼畜就弃了 传送门 题意:带修改点权的最大独立集 N≤1e5N \leq 1e5N≤1e5 一个没啥用的模板,不过适合练习LCT 先写出方程 f(u,0)=∑v∈so ...

  2. 洛谷--橙色百道DP总结

    最近刷完了洛谷橙色DP大约一百道,算是发现了一些套路,就部分题目做一些总结. 大概分为三类 第一类,九大背包及其衍生 第二类,经典DP模型,如LCS,LIS等 第三类,实际问题背景的普通,环形,树上D ...

  3. Educational Codeforces Round 81 (Rated for Div. 2) F.Good Contest \ 洛谷 划艇 组合 计数dp

    cf传送门 P3643 [APIO2016]划艇 文章目录 题意: 思路: 题意: aia_iai​在[li,ri][l_i,r_i][li​,ri​]等概率随机选一个数,求aaa数组不增的概率. 思 ...

  4. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 "低价购买"这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:"低价购买:再低价购买".每次你购买一支股 ...

  5. 洛谷P1244 青蛙过河 DP/思路

    又是一道奇奇怪怪的DP(其实是思路题). 原文戳>>https://www.luogu.org/problem/show?pid=1244<< 这题的意思给的挺模糊,需要一定的 ...

  6. 洛谷 P2657 (数位DP)

    ### 洛谷 P2657 题目链接 ### 题目大意:给你一个数的范围 [A,B] ,问你这段区间内,有几个数满足如下条件: 1.两个相邻数位上的数的差值至少为 2 . 2.不包含前导零. 很简单的数 ...

  7. 洛谷 Golden Sword(dp,优先队列优化【含板子】)|| 补充练习:洛谷 跳房子

    题目链接: 「SWTR-03」Golden Sword - 洛谷 思路: 设表示放第i个原料,锅里共有 j 个时的耐久度之和. 容易知道dp方程为,其中 这样就可以写出暴力dp的代码如下:(需要枚举i ...

  8. 专题·树链剖分【including 洛谷·【模板】树链剖分

    初见安~~~终于学会了树剖~~~ [兴奋]当初机房的大佬在学树剖的时候我反复强调过:"学树剖没有前途的!!!" 恩.真香. 一.重链与重儿子 所谓树剖--树链剖分,就是赋予一个链的 ...

  9. 洛谷·【模板】点分树 | 震波【including 点分树

    初见安-这里是传送门:洛谷P6329 [模板]点分树 | 震波 一.点分树 其实你会点分治的话,点分树就是把点分治时的重心提出来重新连城一棵树. 比如当前点是u,求出子树v的重心root后将root与 ...

  10. 强连通分量:洛谷P3387 模板:缩点

    传送门 顾名思义,模板awa #include <cstdio> #include <cstring> #include <cmath> #include < ...

最新文章

  1. struts2 中 Preparable 接口实现数据准备
  2. 获取NT的admin权限的方法
  3. hdu5386(暴力)
  4. IdentityServer4之JWT签名(RSA加密证书)及验签
  5. 棋魂桌面壁纸图片|大火影视壁纸找高图
  6. vSphere 故障排错思路总结
  7. 一行 Python 代码能实现这么多丧心病狂的功能?
  8. sql server 2014 判断一个列某个字段是否相同_Select * from user的千层套路——一个sql是如何执行的...
  9. Rhino(犀牛)室内模型导入Unity3d快速烘焙光影【2020】
  10. 如何使用imageJ绘制热图 伪彩色
  11. icem二维非结构网格划分_【史上最全轴承结构化网格划分系列】第五弹——自动校准滚针轴承(文末附模型领取方式)...
  12. Single Radio Voice Call Continuity (SRVCC)
  13. wetool 接入图灵机器人_wetool企业版wetool支持微信版本-免费版
  14. 穆迪收购风险与合规情报、数据和软件领域的领导者RDC
  15. Python语法之精妙的十个知识点(装B语法)
  16. 如何成为一名合格的数据产品经理?
  17. Android的apk安装时签名相同冲突解决
  18. 已被Windows defender smartscreen阻止
  19. 关于使用PyQt5时报错This application failed to start because no Qt platform plugin could be initialized及后续问题
  20. 《南瓜书pumpkin-book》项目链接

热门文章

  1. c语言解析分隔符文本,c – 使用分隔符读取文件
  2. linux临时文件创建失败,-bash: 无法为立即文档创建临时文件: 设备上没有空间
  3. 程序代码移植和烧录需要注意什么_购买建站模板需要注意什么问题
  4. 学python多大年龄可以学车_多大年龄可以学驾照?
  5. 深度学习pytorch--线性回归(二)
  6. matlab 三维图像配准,[转载]Matlab实现多种图像配准(转)
  7. indesign中调出字符样式快捷键_Word中十大黄金快捷键,你会用几个?
  8. mysql抓包_mysql抓包工具
  9. 如何取消计算机阻止安装程序,Win10电脑安装软件提示“你必须取消阻止该发布者才能运行此软件”怎么办...
  10. php无法新数据类型,新手入门PHP必知的七种数据类型