方法二:LCT+矩阵乘法
上文中,我们用线段树来维护重链上的各种矩阵转移.
第二种方法是将树链剖分替换为动态树.
我们知道,矩阵乘法 $\begin{bmatrix} F_{u,0} & F_{u,0}\\ F_{u,1}  & -\infty \end{bmatrix}\times\begin{bmatrix} F_{i,0}\\F_{i,1} \end{bmatrix}=\begin{bmatrix} F_{u,0}\\F_{u,1} \end{bmatrix}$ 中第一个矩阵中的每一个 $F_{u,k}$ 都是指考虑轻链时 $u$ 的 DP 值.
在 $LCT$ 中,树的轻重路径是交替变换的.
我们用维护子树信息的方式维护即可.
即设 $tmp$ 矩阵表示该点虚儿子的所有 DP 值的贡献(只是不包括重儿子).
再设 $t$ 矩阵维护 $Splay$ 中的转移.
具体细节看看代码:
 

Code:

// luogu-judger-enable-o2
//Dynamic DP with LCT
#include<bits/stdc++.h>
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
#define maxn 100002
#define inf 100000000
using namespace std;
//Link cut tree
void de()
{
printf("ok\n");
}
namespace LCT
{ struct Matrix
{
ll a[2][2];
ll*operator[](int x){ return a[x];}
}t[maxn],tmp[maxn];
Matrix operator*(Matrix a,Matrix b)
{
Matrix c;
c[0][0]=max(a[0][0]+b[0][0],a[0][1]+b[1][0]);
c[0][1]=max(a[0][0]+b[0][1],a[0][1]+b[1][1]);
c[1][0]=max(a[1][0]+b[0][0],a[1][1]+b[1][0]);
c[1][1]=max(a[1][0]+b[0][1],a[1][1]+b[1][1]);
return c;
} //tmp :: 虚儿子信息
//t :: 树剖实际转移矩阵
#define lson ch[x][0]
#define rson ch[x][1]
int ch[maxn][2],f[maxn];
int isRoot(int x)
{
return !(ch[f[x]][0]==x || ch[f[x]][1]==x);
}
int get(int x)
{
return ch[f[x]][1]==x;
}
void pushup(int x)
{
t[x]=tmp[x];
if(lson) t[x]=t[lson]*t[x];
if(rson) t[x]=t[x]*t[rson];
}
void rotate(int x)
{
int old=f[x],fold=f[old],which=get(x);
if(!isRoot(old)) ch[fold][ch[fold][1]==old]=x;
ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
ch[x][which^1]=old,f[old]=x,f[x]=fold;
pushup(old),pushup(x);
}
void splay(int x)
{
int u=x;
while(!isRoot(u)) u=f[u];
u=f[u];
for(int fa;(fa=f[x])!=u;rotate(x))
if(f[fa]!=u) rotate(get(fa)==get(x)?fa:x);
}
void Access(int x)
{
for(int y=0;x;y=x,x=f[x])
{
splay(x);
if(rson)
{
tmp[x][0][0]+=max(t[rson][0][0],t[rson][1][0]);
tmp[x][1][0]+=t[rson][0][0];
}
if(y)
{
tmp[x][0][0]-=max(t[y][0][0],t[y][1][0]);
tmp[x][1][0]-=t[y][0][0];
}
tmp[x][0][1]=tmp[x][0][0];
rson=y,pushup(x);
}
}
}; //variables
int DP[maxn][2];
int V[maxn],hd[maxn],to[maxn<<1],nex[maxn<<1];
int n,Q,edges;
void add(int u,int v){ nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } //build graph
void dfs(int u,int ff)
{
LCT::f[u]=ff;
DP[u][0]=0;
DP[u][1]=V[u];
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
dfs(v,u);
DP[u][0]+=max(DP[v][1],DP[v][0]);
DP[u][1]+=DP[v][0];
}
LCT::tmp[u]=(LCT::Matrix){ DP[u][0], DP[u][0], DP[u][1], -inf};
LCT::t[u]=LCT::tmp[u];
} //主程序~
int main()
{
// setIO("input");
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;++i) scanf("%d",&V[i]);
for(int i=1,u,v;i<n;++i)
{
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs(1,0);
while(Q--)
{
int x,y;
scanf("%d%d",&x,&y);
LCT::Access(x);
LCT::splay(x);
LCT::tmp[x][1][0]+=(ll)y-V[x];
V[x]=y;
LCT::pushup(x);
LCT::splay(1);
printf("%lld\n",max(LCT::t[1][0][0], LCT::t[1][1][0]));
}
return 0;
}

  

luogu P4719 【模板】动态 DP 矩阵乘法 + LCT的更多相关文章

  1. Luogu P4643 【模板】动态dp(矩阵乘法,线段树,树链剖分)

    题面 给定一棵 \(n\) 个点的树,点带点权. 有 \(m\) 次操作,每次操作给定 \(x,y\) ,表示修改点 \(x\) 的权值为 \(y\) . 你需要在每次操作之后求出这棵树的最大权独立集 ...

  2. [luogu 4719][模板]动态dp

    传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...

  3. 【bzoj2004】[Hnoi2010]Bus 公交线路 状压dp+矩阵乘法

    题目描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计 ...

  4. 【bzoj3329】Xorequ 数位dp+矩阵乘法

    题目描述 输入 第一行一个正整数,表示数据组数据 ,接下来T行每行一个正整数N 输出 2*T行第2*i-1行表示第i个数据中问题一的解, 第2*i行表示第i个数据中问题二的解, 样例输入 1 1 样例 ...

  5. [模板] 动态dp

    用途 对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值 做法(树剖版) 以最大权独立集为例 设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小 ...

  6. 【BZOJ-4386】Wycieczki DP + 矩阵乘法

    4386: [POI2015]Wycieczki Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 197  Solved: 49[Submit][Sta ...

  7. [模板][题解][Luogu1939]矩阵乘法加速递推(详解)

    题目传送门 题目大意:计算数列a的第n项,其中: \[a[1] = a[2] = a[3] = 1\] \[a[i] = a[i-3] + a[i - 1]\] \[(n ≤ 2 \times 10^ ...

  8. LOJ.6074.[2017山东一轮集训Day6]子序列(DP 矩阵乘法)

    题目链接 参考yww的题解.本来不想写来但是他有一些笔误...而且有些地方不太一样就写篇好了. 不知不觉怎么写了这么多... 另外还是有莫队做法的...(虽然可能卡不过) \(60\)分的\(O(n^ ...

  9. ZOJ - 3216:Compositions (DP&矩阵乘法&快速幂)

    We consider problems concerning the number of ways in which a number can be written as a sum. If the ...

随机推荐

  1. N天学习一个linux命令之du

    用途 统计文件或者目录占用硬盘空间大小 用法 du [OPTION] [FILE]du [OPTION] --files0-from=F 常用参数 -a, --all统计所有文件,不仅仅是目录 -b, ...

  2. 从头认识java-15.2 Collection的经常用法(2)-注意点

    上一章节我们讲述了Collection的经常用法.还有之前的章节我们介绍了Collection的addAll方法,这一章节我们介绍一下它的注意点. 注意点就是,在经常用法里面,基本都是可选操作. 什么 ...

  3. golang LMDB入门例子——尼玛,LMDB的文档真的是太少了

    使用的是这个库:https://github.com/szferi/gomdb 安装: go get github.com/szferi/gomdb 代码: package main import ( ...

  4. bzoj 1026 [ SCOI2009 ] windy数 —— 数位DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1026 蛮简单的数位DP,预处理 f[i][j] 表示 i 位数,以 j 开头的 windy ...

  5. 如何在ashx处理页中获取Session值

    本文章摘自:http://www.cnblogs.com/vihone/archive/2010/06/04/1751490.html 在一般事务处理页面,可以轻松的得到 Request,Respon ...

  6. mysql出错代码

    1005:创建表失败 1006:创建数据库失败 1007:数据库已存在,创建数据库失败 1008:数据库不存在,删除数据库失败 1009:不能删除数据库文件导致删除数据库失败 1010:不能删除数据目 ...

  7. thinkphp 日志记录

    日志记录\ThinkPHP\Lib\Think\Core\Log.class.php 1.可以在config.php中进行设置,默认为关闭状态. 'APP_DEBUG' => true 打开\T ...

  8. caffe介绍

  9. A - Word

    Problem description Vasya is very upset that many people on the Net mix uppercase and lowercase lett ...

  10. word文档去掉复制过来的背景颜色

    选择清除格式