方法二: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. hdu_1065_I Think I Need a Houseboat_201311160023

    I Think I Need a Houseboat Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Ja ...

  2. 洛谷——P2639 [USACO09OCT]Bessie的体重问题Bessie's We…

    https://www.luogu.org/problem/show?pid=2639 题目描述 Bessie像她的诸多姊妹一样,因为从Farmer John的草地吃了太多美味的草而长出了太多的赘肉. ...

  3. HDU 5200 脑洞题 离线

    线段树,TLE,各种.唉....我真是笨死了.... 我用的线段树是记录左右区间最长连续棵数的...反正TLE #include <iostream> #include <cstdi ...

  4. IE新发现

    近期用thinkphp写的小程序在IE上測试的时候偶然发现原来IE不兼容的不止是样式啊!!! 震惊哭了~ 在火狐上面嗖嗖的一点bug也没有,在IE上面跟死水一样.. .. 那么问题来了:我的问题是出如 ...

  5. 【 D3.js 进阶系列 — 2.2 】 力学图的參数

    力学图的布局中有非常多參数.本文将逐个说明. D3 中的力学图布局是使用韦尔莱积分法计算的.这是一种用于求解牛顿运动方程的数值方法,被广泛应用于分子动力学模拟以及视频游戏中. 定义布局的代码例如以下: ...

  6. Hypercall

    在Linux中.大家应该对syscall很的了解和熟悉,其是用户态进入内核态的一种途径或者说是一种方式.完毕了两个模式之间的切换:而在虚拟环境中,有没有一种类似于syscall这样的方式.可以从no ...

  7. Android 组件ContentProvider

    Android 组件ContentProvider Android的数据存储有五种方式Shared Preferences.网络存储.文件存储.外储存储.SQLite,一般这些存储都仅仅是在单独的一个 ...

  8. bootstrap异步加载树后样式显示问题

    整个过程: 1.先加载整个页面 2.通过jquery异步请求后台返回数据 3.循环遍历数据,拼接需要的内容 4.把拼接好的数据加载到页面中. 问题: 把拼接好的内容加载到页面后,样式显示不正确.而如果 ...

  9. LMDB中的mmap、Copy On Write、MVCC深入理解——讲得非常好,常来看看!

    LMDB基本架构 lmdb的基本架构如下:  lmdb的基本做法是使用mmap文件映射,不管这个文件存储实在内存上还是在持久存储上.lmdb的所有读取操作都是通过mmap将要访问的文件只读的映射到虚拟 ...

  10. B1024 生日快乐 递归。。。

    bzoj1024叫生日快乐,其实很简单,但是没看出来就很尴尬... Description windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕.现在包括win ...