码迷,mamicode.com
首页 > 其他好文 > 详细

P4719 【模板】动态dp

时间:2018-12-24 13:25:36      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:val   was   ++   show   lct   int   build   ++i   play   

传送门

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_{v\in u.lightson}max(dp_{v,0},dp_{v,1})\]
\[ldp_{u,1}=\sum_{v\in 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]='\n';
}
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

标签:val   was   ++   show   lct   int   build   ++i   play   

原文地址:https://www.cnblogs.com/bztMinamoto/p/10167946.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!