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 ...
随机推荐
- Spring MVC-控制器(Controller)-属性方法名称解析器(Properties Method Name Resolver )示例(转载实践)
以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_propertiesmethodnameresolver.htm 说明:示例基于S ...
- Windows 10卸载Edge浏览器(不成功的别试了)
在命令行输入: PowerShell dir $env:LOCALAPPDATA\Packages\*edge*^|ren -newname MicrosoftEdge.old ; dir $env: ...
- 关于压缩软件gzip和xz的简单对照
晚上因为处理磁盘报警的须要.进行了日志压缩,在此次压缩中分别使用了gzip和xz软件对文本进行了压缩.压缩的结果很令人诧异. 出于对xz好奇的原因是因为在下载内核源码时常常能够看到.xz格式的文件包. ...
- NJUPT JAVA语言 流处理程序设计
一. 实验目的和要求 实验目的和要求:要求学生能在学习和理解课堂学习内容中JAVA流编程理论的基础上,学习并逐步掌握JAVA流程序的编写和调试,学习依据处理需求对不同流的正确选择使用和组合用法. 实验 ...
- Raphaeljs入门到精通(二)
这节我们将介绍Raphaeljs中元素的属性和事件,案例还是以上一篇的代码展开 <!DOCTYPE html> <html xmlns="http://www.w3.org ...
- uva 11605 - Lights inside a 3d Grid(概率)
option=com_onlinejudge&Itemid=8&page=show_problem&problem=2652" style=""& ...
- Android给定坐标计算距离
给定两点的经纬度.计算两点之间的距离.这里要注意经纬度一定要依照顺序填写 1. 利用android中的工具获得,单位是米 float[] results=new float[1]; Location. ...
- velocity.js 中文文档 (教程)
velocity.js 是一个简单易用.高性能.功能丰富的轻量级JS动画库.它能和 jQuery 完美协作,并和$.animate()有相同的 API, 但它不依赖 jQuery,可单独使用. Vel ...
- Spark常见编程问题解决办法及优化
目录 1.数据倾斜 2.TopN 3.Join优化 预排序的join cross join 考虑Join顺序 4.根据HashMap.DF等数据集进行filter 5.Join去掉重复的列 6.展开N ...
- Django day08 多表操作 (二) 添加表记录
一: 一对多 1. 一对多新增 两种方式: publish = 对象 publish_id = id 1. publish_id 和 publish 的区别就是: 1)publish_id 可 ...