方法二: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. php表单常用正则表达式

    <?php /** * @description: 正则表达式匹配 */ class Regex { /** * @手机号 */ public static function Phone($su ...

  2. HDU 4508

    祼的完全背包问题 #include <iostream> #include <cstdio> #include <cstring> #include <alg ...

  3. [Jest] Write data driven tests in Jest with test.each

    Often, we end up creating multiple unit tests for the same unit of code to make sure it behaves as e ...

  4. oracle Plsql 运行update或者delete时卡死问题解决的方法

    oracle Plsql 运行update或者delete时 遇到过Plsql卡死问题或者导致代码运行sql的时候就卡死. 在开发中遇到此问题的时候,本来把sql复制出来,在plsql中运行,Sql本 ...

  5. ExtJs 日期相加,Grid表格列可编辑

    1.日期相加: Ext.Date.add(new Date(), Ext.Date.DAY, 15) 2.Grid表格列可编辑: {    header : "实际已交货量",   ...

  6. android SearchView 样式修改

    try { Class<?> argClass=mSearchView.getClass(); //指定某个私有属性 Field mSearchHintIconField = argCla ...

  7. Elasticsearch源码分析—线程池(十一) ——就是从队列里处理请求

    Elasticsearch源码分析—线程池(十一) 转自:https://www.felayman.com/articles/2017/11/10/1510291570687.html 线程池 每个节 ...

  8. hdu 1213(并查集模版题)

    How Many Tables Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  9. Fishnet(几何)

    http://poj.org/problem?id=1408 题意:给出 a1 a2 ... an                b1 b2 ... bn                c1 c2 . ...

  10. 从0开始学习BFC

    为什么需要BFC? <style> .red { background: red; } .blue { background: #1890ff; } .green { background ...