luoguP4719 【模板】动态 DP 线段树+树链剖分+矩阵乘法+动态DP
题目描述
给定一棵n个点的树,点带点权。
有m次操作,每次操作给定x,y,表示修改点x的权值为y。
你需要在每次操作之后求出这棵树的最大权独立集的权值大小。
输入输出格式
输入格式:
第一行,n,m分别代表点数和操作数。
第二行,V1,V2,...,Vn,代表n个点的权值。
接下来n−1行,x,y,描述这棵树的n−1条边。
接下来m行,x,y,修改点x的权值为y。
输出格式:
对于每个操作输出一行一个整数,代表这次操作后的树上最大权独立集。
保证答案在int范围内
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;
}
我们用矩阵乘法维护每一次链上的转移.

Code:
#include<bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin)
#define maxn 300000
#define lson (now<<1)
#define rson ((now<<1)|1)
#define ll long long
const ll inf = 1e17;
using namespace std;
int hd[maxn],to[maxn],nex[maxn],V[maxn],hson[maxn],fa[maxn],dfn[maxn], ln[maxn],F[maxn][2],siz[maxn],top[maxn],bot[maxn];
int edges,tim,n,Q;
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void dfs1(int u,int ff)
{
siz[u]=1,fa[u]=ff;
for(int i=hd[u];i;i=nex[i])
{
if(to[i]==ff) continue;
dfs1(to[i],u);
siz[u]+=siz[to[i]];
if(siz[to[i]] > siz[hson[u]]) hson[u]=to[i];
}
}
void dfs2(int u,int tp)
{
top[u]=tp,ln[++tim]=u,dfn[u]=tim;
if(hson[u])
dfs2(hson[u], tp), bot[u]=bot[hson[u]];
else
bot[u]=u;
for(int i=hd[u];i;i=nex[i])
{
if(to[i]==fa[u]||to[i]==hson[u]) continue;
dfs2(to[i],to[i]);
}
}
void dfs(int u)
{
F[u][0]=0,F[u][1]=V[u];
for(int i=hd[u];i;i=nex[i])
{
if(to[i]==fa[u]) continue;
dfs(to[i]);
F[u][0]+=max(F[to[i]][1],F[to[i]][0]);
F[u][1]+=F[to[i]][0];
}
}
struct Matrix
{
ll a[2][2];
ll*operator[](int x){ return a[x]; }
}t[maxn<<1],tmp[maxn<<1];
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;
}
void Build(int now,int l,int r)
{
if(l==r)
{
int u=ln[l];
ll g0=0,g1=V[u];
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==fa[u]||v==hson[u]) continue;
g0+=max(F[v][0],F[v][1]);
g1+=F[v][0];
}
t[now]=tmp[l]=(Matrix) {g0,g0,g1,-inf};
return;
}
int mid=(l+r)>>1;
Build(lson,l,mid),Build(rson,mid+1,r);
t[now]=t[lson]*t[rson];
}
void Modify(int now,int l,int r,int p)
{
if(l==r)
{
t[now]=tmp[l];
return;
}
int mid=(l+r)>>1;
if(p<=mid) Modify(lson,l,mid,p);
else Modify(rson,mid+1,r,p);
t[now]=t[lson]*t[rson];
}
Matrix Query(int now,int l,int r,int L,int R)
{
if(L==l&&r==R) return t[now];
int mid=(l+r)>>1;
if(R<=mid) return Query(lson,l,mid,L,R);
if(L>mid) return Query(rson,mid+1,r,L,R);
return Query(lson,l,mid,L,mid)*Query(rson,mid+1,r,mid+1,R);
}
void Update(int u,int w)
{
tmp[dfn[u]][1][0]+=w-V[u],V[u]=w;
while(u)
{
Matrix a=Query(1,1,n,dfn[top[u]],dfn[bot[u]]);
Modify(1,1,n,dfn[u]);
Matrix b=Query(1,1,n,dfn[top[u]],dfn[bot[u]]);
u=fa[top[u]];
if(!u) break;
int x = dfn[u];
ll g0=a[0][0],g1=a[1][0],f0=b[0][0],f1=b[1][0];
tmp[x][0][0]=tmp[x][0][1]=tmp[x][0][0]+max(f0,f1)-max(g0,g1);
tmp[x][1][0]=tmp[x][1][0]+f0-g0;
}
}
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);
}
dfs1(1,0),dfs2(1,1),dfs(1),Build(1,1,n);
while(Q--)
{
int x,w;
scanf("%d%d",&x,&w);
Update(x,w);
Matrix ans=Query(1,1,n,dfn[1],dfn[bot[1]]);
printf("%lld\n",max(ans[0][0],ans[1][0]));
}
return 0;
}
luoguP4719 【模板】动态 DP 线段树+树链剖分+矩阵乘法+动态DP的更多相关文章
- 51nod 1462 树据结构 | 树链剖分 矩阵乘法
题目链接 51nod 1462 题目描述 给一颗以1为根的树. 每个点有两个权值:vi, ti,一开始全部是零. Q次操作: 读入o, u, d o = 1 对u到根上所有点的vi += d o = ...
- 形态形成场(矩阵乘法优化dp)
形态形成场(矩阵乘法优化dp) 短信中将会涉及前\(k\)种大写字母,每个大写字母都有一个对应的替换式\(Si\),替换式中只会出现大写字母和数字,比如\(A→BB,B→CC0,C→123\),代表 ...
- 【bzoj1778】[Usaco2010 Hol]Dotp 驱逐猪猡 矩阵乘法+概率dp+高斯消元
题目描述 奶牛们建立了一个随机化的臭气炸弹来驱逐猪猡.猪猡的文明包含1到N (2 <= N <= 300)一共N个猪城.这些城市由M (1 <= M <= 44,850)条由两 ...
- 斐波那契数列 矩阵乘法优化DP
斐波那契数列 矩阵乘法优化DP 求\(f(n) \%1000000007\),\(n\le 10^{18}\) 矩阵乘法:\(i\times k\)的矩阵\(A\)乘\(k\times j\)的矩 ...
- 线段树&数链剖分
傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ...
- 【清澄A1333】【整体二分+二维树状数组】矩阵乘法(梁盾)
试题来源 2012中国国家集训队命题答辩 问题描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入格式 第一行两个数N,Q,表示矩阵大小和询问组数: 接下来N行N列一共 ...
- 矩阵乘法优化DP复习
前言 最近做毒瘤做多了--联赛难度的东西也该复习复习了. Warning:本文较长,难度分界线在"中场休息"部分,如果只想看普及难度的可以从第五部分直接到注意事项qwq 文中用(比 ...
- [BZOJ 1009] [HNOI2008] GT考试 【AC自动机 + 矩阵乘法优化DP】
题目链接:BZOJ - 1009 题目分析 题目要求求出不包含给定字符串的长度为 n 的字符串的数量. 既然这样,应该就是 KMP + DP ,用 f[i][j] 表示长度为 i ,匹配到模式串第 j ...
- 矩阵乘法优化DP
本文讲一下一些基本的矩阵优化DP的方法技巧. 定义三个矩阵A,B,C,其中行和列分别为$m\times n,n \times p,m\times p$,(其中行是从上往下数的,列是从左往右数的) $C ...
随机推荐
- 关于linux中使用vim打开文件出现^M的解决方法
在linux下,不可避免的会用VIM打开一些windows下编辑过的文本文件.我们会发现文件的每行结尾都会有一个^M符号,这是因为 DOS下的编辑器和Linux编辑器对文件行末的回车符处理不一致, 各 ...
- CF #319 div 2 D
这道题算不算脑洞题.. 可以发现,当一个排列中有循环节时长度为1或2时可能有解.当为1时,只需把全部点都连到这个题即可,当为2时,就要求所有循环节长度均为偶数,这很容易理解,因为如果存在为奇数,它们之 ...
- powerdesigner 16.5 视图的显示
今天中午为了解说绘图.然后把toolbox跟object brower都关掉了,花了1个小时才找到toolbox 1.object brower显示 直接使用快捷键 ALT+0 2.toolbox(也 ...
- JSONObject.toBean() data转换
//toBean方法不识别date属性 要把VO的DATE该成UTIL包下的DATE 然后加上下面的代码.不然会报错JSONUtils.getMorpherRegistry().registerMo ...
- linux下获取按键响应事件【转】
本文转载自:https://my.oschina.net/u/157503/blog/91548 1.问题 通过一个死循环将读取键盘对应的设备文件将触发键盘事件在屏幕上打印出来,按esc退出程序 代码 ...
- bzoj5130: [Lydsy1712月赛]字符串的周期
这道题很有意思啊. 字符串循环节用KMP(手推一下) 假如是26^12肯定很不滋磁 但是可以发现ABA和BCB和BAB这些都是等价的 那就把最小的拿出来搞再乘个排列数就好了 #include<c ...
- C# Path 有关于文件路径等问题类(转)
C# Path 标签:C#, Path C-Sharp 0 Path handles file path processing. The .NET Framework provides effect ...
- Your configuration specifies to merge with the ref 'refs/heads/v.autoCheckProduct.20190325' from the remote, but no such ref was fetched.
问题: 创建新的分支,当我们执行git pull,出现如下错误 解决办法: 1.切换到主分支(或者被依赖的分支,也就是你从哪个分支上拉取新的分支),博主这里是master分支 2.执行以下两个命令 3 ...
- MSSQL:删除系统作业计划
use [msdb]declare @job_name varchar(100)set @job_name = N'EveryDayBackup.Subplan_1'--注:jobName为维护计划对 ...
- UIView动画基础
1 Position 平移 [UIView animateWithDuration:1.0 animations:^{ _blueView.centerX = self.view.width -100 ...