P4719 模板动态dp
Posted bztminamoto
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4719 模板动态dp相关的知识,希望对你有一定的参考价值。
shadowice巨巨太强啦
表示连树剖都不会直接来肝这个近乎LCT的很懵逼啊……于是一个晚上就过去了……
首先,这题本质上就是个没有上司的舞会,然而带修改
先考虑正常的dp方程,设(dp_{u,0})表示该点不选的最大收益,(dp_{u,1})表示该点选的最大收益,则有[dp_{u,0}=sum max(dp_{v,0},dp_{v,1})]
[dp_{u,1}=val_u+sum dp_{v,0}]
我们考虑一下把整棵树给树剖,一条一条重链来求出dp值。每一次到一条重链的时候,先递归下去吧所有与它相连的其他重链给dp完,然后再来求出它的dp值。算这条重链的时候,先算出轻儿子的dp值,设为(ldp_{u,0/1}),则有[ldp_{u,0}=sum_{vin u.lightson}max(dp_{v,0},dp_{v,1})]
[ldp_{u,1}=sum_{vin u.lightson}dp_{v,0}]
那么重链上的dp就可以放到一个序列上进行了
[dp_{u,0}=ldp_{u,0}+max(dp_{u.heavyson,0},dp_{u.heavyson,1})]
[dp_{u,1}=val_u+ldp_{1,u}+dp_{u.heavyson,0}]
于是我们现在就把一个树上的问题转化为了一个序列的问题,每一次单点修改的时候可以在线段树上对应的重链进行修改,那么会改变重链顶点的dp值,于是又要改变重链顶点父亲的dp值,这样不断搞上去,就可以用树剖做到(O(log^2n))了
然后关于怎么在线段树上维护dp值,据猫老师说,我们可以重定义一个矩乘,即[C_{i,j}=max_k(A_{i,k}+B_{k,j})]
而且这个新的矩乘还是满足结合律的(不过不满足交换律),单位矩阵是主对角线上是(0),其他全都是(-infty),那么重链的转移可以写成矩乘的形式,那么就可以在线段树上维护矩阵连乘积了
以上是树剖的做法,然后是shadowice巨巨说的“全局平衡二叉树”
具体来说,就是把树剖换成LCT,再通过一些手段来减小LCT的常数,从而达到优化时间复杂度的目的
首先这是棵静态树,建LCT没有必要,所以把LCT给静态化
我们先对原树进行一遍dfs,然而在对重链建bst并不建一个严格的bst,在每一个节点设一个权值,为它所有轻儿子的(size)总和,然后选择带权重心作为这一级的父亲,递归往两边建bst
然后发现在这棵树里面从底往上经过的不管是实边还是虚边,子树的(size)都会翻一倍,所以这个树的树高是(O(logn))的
于是这玩意儿就能做到(O(nlogn))的时间复杂度了
//minamoto
#include<bits/stdc++.h>
#define R register
#define inf 0x3f3f3f3f
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='
';
}
inline int min(R int x,R int y){return x<y?x:y;}
inline int max(R int x,R int y){return x>y?x:y;}
const int N=1e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int sz[N],son[N],val[N],n,m;
void dfs(int u,int fa){
sz[u]=1;go(u)if(v!=fa){
dfs(v,u),sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
struct Matrix{
int a[2][2];
Matrix(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=-inf;}
Matrix(R int x){a[0][0]=a[1][1]=0,a[0][1]=a[1][0]=-inf;}
inline int mx(){return max(max(a[0][0],a[0][1]),max(a[1][0],a[1][1]));}
inline int* operator [](R int x){return a[x];}
Matrix operator *(Matrix b){
Matrix res;
res[0][0]=max(a[0][0]+b[0][0],a[0][1]+b[1][0]);
res[0][1]=max(a[0][0]+b[0][1],a[0][1]+b[1][1]);
res[1][0]=max(a[1][0]+b[0][0],a[1][1]+b[1][0]);
res[1][1]=max(a[1][0]+b[0][1],a[1][1]+b[1][1]);
return res;
}
}mul[N],w[N];int ch[N][2],fa[N],st[N],lsz[N],top,rt;bool vis[N];
inline void upd(R int x){mul[x]=mul[ch[x][0]]*w[x]*mul[ch[x][1]];}
inline void pd(R int x,R int v){
w[x][1][0]+=mul[v].mx(),w[x][0][0]=w[x][1][0],w[x][0][1]+=mul[v][0][0],fa[v]=x;
}
inline void init(){fp(i,1,n)w[i][0][1]=val[i],w[i][0][0]=w[i][1][0]=0;}
inline bool is(R int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
int sbuild(int l,int r){
if(l>r)return 0;int tot=0;for(int i=l;i<=r;++i)tot+=lsz[st[i]];
for(int i=l,now=lsz[st[i]];i<=r;++i,now+=lsz[st[i]])
if(2*now>=tot){
ch[st[i]][0]=sbuild(i+1,r),ch[st[i]][1]=sbuild(l,i-1);
fa[ch[st[i]][0]]=fa[ch[st[i]][1]]=st[i],upd(st[i]);return st[i];
}
}
int build(int x){
for(int p=x;p;p=son[p])vis[p]=1;
for(int p=x;p;p=son[p])go(p)if(!vis[v])pd(p,build(v));
top=0;for(int p=x;p;p=son[p])st[++top]=p;
for(int p=x;p;p=son[p])lsz[p]=sz[p]-sz[son[p]];return sbuild(1,top);
}
void update(int x,int vva){
w[x][0][1]+=vva-val[x],val[x]=vva;
for(int p=x;p;p=fa[p])if(is(p)&&fa[p]){
w[fa[p]][0][0]-=mul[p].mx(),w[fa[p]][1][0]=w[fa[p]][0][0];
w[fa[p]][0][1]-=mul[p][0][0],upd(p);
w[fa[p]][0][0]+=mul[p].mx(),w[fa[p]][1][0]=w[fa[p]][0][0];
w[fa[p]][0][1]+=mul[p][0][0];
}else upd(p);
}
int main(){
// freopen("testdata.in","r",stdin);
w[0]=mul[0]=Matrix(1),n=read(),m=read();
fp(i,1,n)val[i]=read();
for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
dfs(1,0),init(),rt=build(1);int p,w;
while(m--)p=read(),w=read(),update(p,w),print(mul[rt].mx());
return Ot(),0;
}
以上是关于P4719 模板动态dp的主要内容,如果未能解决你的问题,请参考以下文章