动态DP学习笔记

动态DP学习笔记

动态DP实际上就是利用树链剖分的性质快速的维护\(f\)\(g\),利用矩阵乘法和线段树加速修改过程
\(f\)数组的用途在本质上与LCT动态维护树的重心那个轻儿子子树的用途相同,用来“填”重链维护中留下的坑
水平不行 说不清楚。。。 还是代码最直观。。。
注意矩阵乘法不满足交换律 维护线段树时要注意一下从哪边向哪边合并
还有矩阵乘法最后要return 写函数变量不要重名!!!

/*
注意Matrix的乘法函数
最后要return!!!
否则会出现未知错误。。。 
*/
#include<stack>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int U=2,N=1e5+10,M=2e5+10,INF=0x3f3f3f3f;
inline void Read(int &x){
    x=0;register char cc='\0';int fff=1;
    for(;cc<'0'||cc>'9';cc=getchar())if(cc=='-')fff=-1;
    for(;cc>='0'&&cc<='9';cc=getchar())x=(x<<1)+(x<<3)+(cc&15);
    x*=fff;
}
int n,m,num,fa[N],val[N],siz[N],dfn[N],real[N];
int tot,bson[N],Top[N],Tail[N],Head[N],Next[M],Adj[M];
struct Matrix{
    int len1,len2,t[U][U];
    Matrix operator * (const Matrix Other) const{
        Matrix c;c.len1=len1;c.len2=Other.len2;
        memset(c.t,0xcf,sizeof(c.t));
        for(int k=0;k<2;++k)
            for(int i=0;i<2;++i)
                for(int j=0;j<2;++j)
                    c.t[i][j]=max((LL)c.t[i][j],(LL)t[i][k]+Other.t[k][j]);
        return c;//!!!!!
    }

}G[N],Tree[N<<2];
inline void Pushup(int now){Tree[now]=Tree[now<<1]*Tree[now<<1|1];}
void Update(const int ed,const Matrix ad,int now=1,int nowl=1,int nowr=n){
    if(nowl==nowr){
        Tree[now]=ad;
        return;
    }
    int nowm=(nowl+nowr)>>1;
    if(ed<=nowm)Update(ed,ad,now<<1,nowl,nowm);
    if(ed>nowm)Update(ed,ad,now<<1|1,nowm+1,nowr);
    Pushup(now);
}
Matrix Query(int left,int right,int now=1,int nowl=1,int nowr=n){
    if(left<=nowl&&nowr<=right) return Tree[now];
    int nowm=(nowl+nowr)>>1;
    if(right<=nowm)return Query(left,right,now<<1,nowl,nowm);
    if(left>nowm)return Query(left,right,now<<1|1,nowm+1,nowr);
    return Query(left,nowm,now<<1,nowl,nowm)
    *Query(nowm+1,right,now<<1|1,nowm+1,nowr);
}
void DFS1(int now,int fat){
    fa[now]=fat;siz[now]=1;
    for(int e=Head[now];e;e=Next[e])
        if(Adj[e]!=fat){
            DFS1(Adj[e],now);siz[now]+=siz[Adj[e]];
            if(siz[Adj[e]]>siz[bson[now]])bson[now]=Adj[e];
        }
}
void DFS2(int now,int fat){
    fa[now]=fat;
    real[dfn[now]=++num]=now;
    if(now==bson[fat])Top[now]=Top[fat];
    else Top[now]=now;
    if(bson[now])DFS2(bson[now],now);
    for(int e=Head[now];e;e=Next[e])
        if(Adj[e]!=fat&&Adj[e]!=bson[now])
            DFS2(Adj[e],now);
    Tail[now]=bson[now]?Tail[bson[now]]:now;
}
void Prepare(int now){/*预处理F,G*/
    stack<int> S;while(!S.empty())S.pop();
    for(int i=now;i;i=bson[/*now*/i])S.push(i);
    while(!S.empty()){
        int /*now*/u=S.top();S.pop();
        int x=0,y=val[/*now*/u];
        for(int e=Head[/*now*/u];e;e=Next[e]){
            if(Adj[e]!=fa[/*now*/u]&&Adj[e]!=bson[/*now*/u]){
                Prepare(Adj[e]);
                Matrix q=G[Adj[e]];
                x+=max(q.t[0][0],q.t[1][0]);
                y+=q.t[0][0];
            }
        }
        Matrix q=(Matrix){2,2,{{x,x},{y,-INF}}};
        Update(dfn[/*now*/u],q);
    }
    G[now]=Query(dfn[now],dfn[Tail[now]]);
    /*回溯时计算以自己为Top的重链上的贡献!!!*/
}
void Modify(int now,int vl){
    Matrix q=Query(dfn[now],dfn[now]);
    q.t[1][0]-=val[now];val[now]=vl;q.t[1][0]+=val[now];
    Update(dfn[now],q);
    for(int u=Top[now],ft=fa[Top[now]];u;u=Top[ft]){
        ft=fa[u];
        int x=G[u].t[0][0],y=G[u].t[1][0];
        G[u]=Query(dfn[u],dfn[Tail[u]]);
        if(ft){
            Matrix p=Query(dfn[ft],dfn[ft]);
            p.t[0][0]+=max(G[u].t[0][0],G[u].t[1][0])-max(x,y);
            p.t[0][1]=p.t[0][0];
            p.t[1][0]+=G[u].t[0][0]-x;
            Update(dfn[ft],p);
        }
    }
}
int main()
{
    freopen("LG4719.in","r",stdin);
    freopen("LG4719.out","w",stdout);
    Read(n);Read(m);
    for(int i=0;i<(N<<2);++i)Tree[i].len1=Tree[i].len2=2;
    for(int i=0;i<N;++i)G[i].len1=G[i].len2=2;
    for(int i=1;i<=n;++i)Read(val[i]);
    for(int i=1,x,y;i<n;++i){
        Read(x);Read(y);
        Next[++tot]=Head[x];Head[x]=tot;Adj[tot]=y;
        Next[++tot]=Head[y];Head[y]=tot;Adj[tot]=x;
    }
    DFS1(1,0);DFS2(1,0);
    Prepare(1);
    while(m--){
        int x,y;Read(x);Read(y);
        Modify(x,y);Matrix nas=Query(dfn[1],dfn[Tail[1]]);
        printf("%d\n",max(nas.t[0][0],nas.t[1][0]));
    }
    return 0;
}

转载于:https://www.cnblogs.com/ZICLEX/p/10249401.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值