洛谷P4719 【模板】"动态 DP"&动态树分治
日常懵逼
先不考虑修改,就是一个很基础的没有上司的舞会。
定义状态表示以为根且 不选/选 的最大权独立集
显然有转移:
考虑修改时,只会对她上面的链上的节点产生影响。
由于树可能会退化成一条链,那么修改一次更新的时间复杂度就是,不可接受。
所以需要用重链剖分。
重链剖分有以下性质能够保证快速修改:
1.每个点到根的路径上,最多经过条轻边,那么重链最多条,保证时间复杂度
2.重链剖分中,一条重链在剖出的上是连续的一段区间,保证可以用数据结构维护,能够快速转移。
3.每条重链的链尾都是叶节点,而且只有叶节点没有重儿子,保证了状态转移方向。
我们先做一个树剖,然后一条重链,一条重链地进行
然后设表示只考虑轻儿子的值
有如下转移:
然后可以写出矩阵的形式:
然后就可以树剖+线段树维护,修改时改重链链顶就可以了。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
#define N 100005
#define INF 0x3f3f3f3f
#define LL long long
int rd()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
return f*x;
}
int n;
struct Matrix{
int m[3][3];
int* operator [](int i){ return m[i]; }
};
Matrix operator * (Matrix a,Matrix b)
{
Matrix c;
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
c[i][j]=-INF;
for(int i=1;i<=2;i++)
for(int k=1;k<=2;k++)
for(int j=1;j<=2;j++)
c[i][j]=max(c[i][j],a[i][k]+b[k][j]);
return c;
}
Matrix tree[N<<2],g[N];
vector<int>G[N];
int a[N],fat[N],siz[N],hson[N],dep[N];
int tp[N],ed[N],dfn[N],tid[N],dfc;
int f[N][2];//f[i][1]以i为根且i选的最大权独立集 f[i][0]不选i
void dfs(int u,int fa)
{
int mx=0;
fat[u]=fa;
siz[u]=1;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
if(siz[v]>mx)
mx=siz[v],hson[u]=v;
}
}
void dfs2(int u,int Top)
{
dfc++;
dfn[u]=dfc;
tid[dfn[u]]=u;
tp[u]=Top;
ed[tp[u]]=dfn[u];
f[u][0]=g[u][1][1]=0;
f[u][1]=g[u][2][1]=a[u];
if(hson[u])
{
dfs2(hson[u],Top);
f[u][1]+=f[hson[u]][0];
f[u][0]+=max(f[hson[u]][0],f[hson[u]][1]);
}
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==fat[u]||v==hson[u]) continue;
dfs2(v,v);
g[u][2][1]+=f[v][0],g[u][1][1]+=max(f[v][0],f[v][1]);
f[u][1]+=f[v][0],f[u][0]+=max(f[v][0],f[v][1]);
}
g[u][1][2]=g[u][1][1];
}
void PushUp(int i)
{
tree[i]=tree[i<<1]*tree[i<<1|1];
}
void Build(int i,int l,int r)
{
if(l==r)
{
tree[i]=g[tid[l]];
return ;
}
int mid=(l+r)>>1;
Build(i<<1,l,mid);
Build(i<<1|1,mid+1,r);
PushUp(i);
}
void Update(int i,int l,int r,int pos)
{
if(l==r)
{
tree[i]=g[tid[pos]];
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) Update(i<<1,l,mid,pos);
else Update(i<<1|1,mid+1,r,pos);
PushUp(i);
}
Matrix Query(int i,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return tree[i];
int mid=(l+r)>>1;
if(qr<=mid) return Query(i<<1,l,mid,ql,qr);
else if(ql>mid) return Query(i<<1|1,mid+1,r,ql,qr);
return Query(i<<1,l,mid,ql,qr)*Query(i<<1|1,mid+1,r,ql,qr);
}
void Modify(int u,int val)
{
g[u][2][1]+=val-a[u],a[u]=val;
while(u)
{
Matrix x=Query(1,1,n,dfn[tp[u]],ed[tp[u]]);
Update(1,1,n,dfn[u]);
Matrix y=Query(1,1,n,dfn[tp[u]],ed[tp[u]]);
u=fat[tp[u]];
g[u][1][1]+=max(y[1][1],y[2][1])-max(x[1][1],x[2][1]);
g[u][1][2]=g[u][1][1];
g[u][2][1]+=y[1][1]-x[1][1];
}
}
int main()
{
n=rd();int Q=rd();
for(int i=1;i<=n;i++)
a[i]=rd();
for(int i=1;i<=n-1;i++)
{
int u=rd(),v=rd();
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
dfs2(1,1);
Build(1,1,n);
while(Q--)
{
int u=rd(),val=rd();
Modify(u,val);
Matrix ans=Query(1,1,n,1,ed[1]);
printf("%d\n",max(ans[1][1],ans[2][1]));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现