洛谷P4719 【模板】"动态 DP"&动态树分治
日常懵逼
先不考虑修改,就是一个很基础的没有上司的舞会。
定义状态\(f[i][0/1]\)表示以\(i\)为根且 不选/选 \(i\)的最大权独立集
显然有转移:
\(f[u][0]=\sum max(f[v][0],f[v][1])\)
\(f[u][1]=\sum f[v][0] + a[u]\)
考虑修改时,只会对她上面的链上的节点产生影响。
由于树可能会退化成一条链,那么修改一次更新的时间复杂度就是\(O(n)\),不可接受。
所以需要用重链剖分。
重链剖分有以下性质能够保证快速修改:
1.每个点到根的路径上,最多经过\(log(n)\)条轻边,那么重链最多\(log(n)\)条,保证时间复杂度
2.重链剖分中,一条重链在剖出的\(dfn\)上是连续的一段区间,保证可以用数据结构维护,能够快速转移。
3.每条重链的链尾都是叶节点,而且只有叶节点没有重儿子,保证了状态转移方向。
我们先做一个树剖,然后一条重链,一条重链地进行\(dp\)
然后设\(g[i][0/1]\)表示只考虑轻儿子的\(dp\)值
有如下转移:
\(f[i][0]=max(f[hson][0],f[hson][1])+g[i][0]\)
\(f[i][1]=f[hson][0]+g[i][1]\)
然后可以写出矩阵的形式:
\[\begin{bmatrix}
f[i][0] \\
f[i][1] \\
\end{bmatrix} =
\begin{bmatrix}
g[i][0] &g[i][0] \\
g[i][1] & -∞ \\
\end{bmatrix} \times
\begin{bmatrix}
f[hson][0] \\
f[hson][1] \\
\end{bmatrix}
\]
然后就可以树剖+线段树维护,修改时改重链\(f[]\)链顶\(g[]\)就可以了。
#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;
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com