题目

尽管知道这个东西应该不会考了,但是还是学一学吧

哎要是去年noip之前学该多好

动态\(dp\)就是允许修改的一个\(dp\),比如这道题,我们都知道这是一个树上最大点权独立集

众所周知方程长这个样子

\[dp_{u,0}=\sum_{(u,v)\in e}min(dp_{v,0},dp_{v.1})
\]

\[dp_{u,1}=a_v+\sum_{(u,v)\in e}dp_{v,0}
\]

但是有了修改我们就没有办法做了

写不下去了,挂一个yyb跑路吧

大概就是一句话,维护处每一个点的轻儿子的转移矩阵,由于一个链的链底没有儿子,于是整个重链乘起来就是答案

放上板子

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define inf 999999999999
#define re register
#define maxn 100005
inline int read() {
char c=getchar();int x=0,r=1;
while(c<'0'||c>'9') {if(c=='-') r=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x*r;
}
inline LL max(LL a,LL b) {return a>b?a:b;}
struct mat{LL a[2][2];}d[maxn<<2];
mat operator*(mat a,mat b) {
mat c;
c.a[0][0]=max(a.a[0][0]+b.a[0][0],a.a[0][1]+b.a[1][0]);
c.a[0][1]=max(a.a[0][1]+b.a[1][1],a.a[0][0]+b.a[0][1]);
c.a[1][0]=max(a.a[1][0]+b.a[0][0],a.a[1][1]+b.a[1][0]);
c.a[1][1]=max(a.a[1][1]+b.a[1][1],a.a[1][0]+b.a[0][1]);
return c;
}
struct E{int v,nxt;}e[maxn<<1];
int sum[maxn],dfn[maxn],top[maxn],son[maxn],deep[maxn],fa[maxn],mx[maxn];
LL dp[maxn][2];int head[maxn],a[maxn],pos[maxn],to[maxn];
int n,m,num,__;
int l[maxn<<2],r[maxn<<2];
inline void C(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
void dfs1(int x) {
sum[x]=1;int maxx=-1;
for(re int i=head[x];i;i=e[i].nxt) {
if(deep[e[i].v]) continue;
deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
dfs1(e[i].v);sum[x]+=sum[e[i].v];
if(sum[e[i].v]>maxx) son[x]=e[i].v,maxx=sum[e[i].v];
}
}
void dfs2(int x,int topf) {
top[x]=topf,dfn[x]=++__,to[__]=x;
if(!son[x]) return;
dfs2(son[x],topf);
for(re int i=head[x];i;i=e[i].nxt) {
if(top[e[i].v]) continue;
dfs2(e[i].v,e[i].v);
}
}
inline void pushup(int i) {d[i]=d[i<<1]*d[i<<1|1];}
void add(int i,int val) {d[i].a[1][0]+=val;while(i) {i>>=1;pushup(i);}}
void change(int i,mat val) {d[i]=val;while(i) {i>>=1;pushup(i);}}
void build(int x,int y,int i) {
l[i]=x,r[i]=y;
if(x==y) {
int now=to[x];dp[now][1]+=a[now];
for(re int j=head[now];j;j=e[j].nxt) {
if(deep[e[j].v]<deep[now]) continue;
if(e[j].v==son[now]) continue;
dp[now][0]+=max(dp[e[j].v][1],dp[e[j].v][0]);
dp[now][1]+=dp[e[j].v][0];
}
d[i].a[0][0]=dp[now][0],d[i].a[0][1]=dp[now][0];
d[i].a[1][0]=dp[now][1],d[i].a[1][1]=-inf;
if(son[now])
dp[now][0]+=max(dp[son[now]][1],dp[son[now]][0]),dp[now][1]+=dp[son[now]][0];
pos[now]=i;
return;
}
int mid=x+y>>1;
build(mid+1,y,i<<1|1),build(x,mid,i<<1);
pushup(i);
}
mat query(int x,int y,int i) {
if(x<=l[i]&&y>=r[i]) return d[i];
int mid=l[i]+r[i]>>1;
if(y<=mid) return query(x,y,i<<1);
if(x>mid) return query(x,y,i<<1|1);
return query(x,y,i<<1)*query(x,y,i<<1|1);
}
int main() {
n=read(),m=read();
for(re int i=1;i<=n;i++) a[i]=read();
for(re int x,y,i=1;i<n;i++) {
x=read(),y=read();C(x,y),C(y,x);
}
deep[1]=1,dfs1(1),dfs2(1,1),build(1,n,1);
for(re int i=1;i<=n;i++)
if(deep[i]>deep[mx[top[i]]]) mx[top[i]]=i;
for(re int x,y,i=1;i<=m;i++){
x=read(),y=read();
mat pre=query(dfn[top[x]],dfn[mx[top[x]]],1);
add(pos[x],-a[x]+y);a[x]=y;
while(x) {
if(top[x]==1) break;
mat now=query(dfn[top[x]],dfn[mx[top[x]]],1);
mat t=d[pos[fa[top[x]]]];
t.a[0][0]-=max(pre.a[0][0],pre.a[1][0]),t.a[0][1]=t.a[0][0];
t.a[1][0]-=pre.a[0][0];
t.a[0][0]+=max(now.a[0][0],now.a[1][0]),t.a[0][1]=t.a[0][0];
t.a[1][0]+=now.a[0][0];
x=fa[top[x]];
pre=query(dfn[top[x]],dfn[mx[top[x]]],1);
change(pos[x],t);
}
mat s=query(1,dfn[mx[1]],1);
printf("%lld\n",max(s.a[0][0],s.a[1][0]));
}
return 0;
}

「LGP4719【模板】动态dp」的更多相关文章

  1. 「单调队列优化DP」P2034 选择数字

    「单调队列优化DP」P2034 选择数字 题面描述: 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入格 ...

  2. Note -「动态 DP」学习笔记

    目录 「CF 750E」New Year and Old Subsequence 「洛谷 P4719」「模板」"动态 DP" & 动态树分治 「洛谷 P6021」洪水 「S ...

  3. [HNOI2007]梦幻岛宝珠 「套路:分层 $DP$」

    显然直接 \(01\) 背包会超时并且超空间 套路:分层 \(DP\) 「考虑将每个子结构看作一层(也就是包含了不止 \(1\) 个物品的信息),并且大层不会对小层造成影响,可以考虑先进行每一层的自我 ...

  4. [模板] 动态dp

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

  5. 「BZOJ 4565」「HAOI 2016」字符合并「区间状压DP」

    题意 给一个长度为\(n(\leq 300)\)的\(01\)串,每次可以把\(k(\leq 8)\)个相邻字符合并,得到新字符和一定分数,最大化最后的得分 题解 考虑设计dp:\(dp[S][i][ ...

  6. 「树形结构 / 树形DP」总结

    Codeforces 686 D. Kay and Snowflake 要求$O(n)$求出以每个节点为根的重心. 考虑对于一个根节点$u$,其重心一定在[各个子树的重心到$u$]这条链上.这样就能够 ...

  7. 「概率,期望DP」总结

    期望=Σ概率*权值 1. Codeforces 148-D 考虑用$f[i][j]$表示princess进行操作时[还剩有i只w,j只b]这一状态的存在概率.这一概率要存在,之前draw out的一定 ...

  8. 「LG4782 模板 2-SAT 问题」

    题目 来学\(2\)-\(sat\)了 这个东西确实不难 这个算法就是给你一堆\(bool\)变量\(x_1,x_2...x_n\),之后给你一些限制 限制的形式就是给你一对\((u,o1,v,o2) ...

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

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

随机推荐

  1. HTML基础-常用标签及图片

    标记/标签{元素} 双标签: <标签>内容</标签> <html></html>    网页 页面的根元素 <head></head& ...

  2. 关于键盘KeyDown事件

    if (e.KeyValue==13) //如果键盘的值等于13 这里面的13是enter键 textBox2.Focus(); //焦点就跑到textbox2上面

  3. RichTextBox控件

    RichTextBox控件允许用户输入和编辑文本的同时提供了比普通的TextBox控件更高级的格式特征 //color在c#中是个枚举enum 蓝色按钮:在蓝色按钮注册click事件后,richtex ...

  4. MySQL---8、索引

    1.索引中关于搜索的算法  2.索引的使用原则  3.索引的优缺点  4.索引的种类  5.显示索引 show index from 表名;  6.创建唯一索引 alter table 表名 add ...

  5. 利用三层判断sql数据库中编码是否已经存在(个人拙作,不喜勿喷)

    本人.Net新手,初学三层便想记录写笔记,以供像自己一样的新人去学习,大神就不用看啦 Dal层: /// 判断编码是否存在 /// </summary> /// <param nam ...

  6. Java 锁机制总结

    锁的种类 独享锁 VS 共享锁 独享锁:锁只能被一个线程持有(synchronized) 共享锁:锁可以被多个程序所持有(读写锁) 乐观锁 VS 悲观锁 乐观锁:每次去拿数据的时候都乐观地认为别人不会 ...

  7. Java SE 8 的流库学习笔记

    前言:流提供了一种让我们可以在比集合更高的概念级别上指定计算的数据视图.如: //使用foreach迭代 long count = 0; for (String w : words) { if (w. ...

  8. UTF-8和GBK编码转换iconv

    iconv("GBK", "UTF-8", $str);//将GBK编码转换成UTF8编码

  9. jQuery的attr()与prop()的区别

    jQuery的attr()与prop()都是用于获取与设置属性的,但它们又各有不同. attr()一般是用于设置默认值,prop()一般是用于设置属性值,即对于像“diabled”,"che ...

  10. arcgis for js/flex/sl 该选哪一个?

    arcgis server开发webgis 在客户端有3种选择:js.flex.sl 他们除了开发arcgis外,本身还有一些常用的领域 js:在传统网站中很常用 flex:游戏.视频播放.动画特效 ...