luogu P4719 【模板】动态dp

noip怎么考这种东西啊。。。看错题场上爆零凉了

首先我们先进行树链剖分,那么问题可以转换成重链的答案+其他子节点的答案

而每次修改相当于改一段重链的答案,改一次其他子节点的答案交替进行

这样只有一个好处,就是把问题转换成序列问题,可以用线段树优化

fx,1表示不选当前点的最优解,fx,2表示选 方程很好列不写了

lx,1表示不选当前点,不管重儿子那边的最优解

为了加速我们转移套一个矩乘,(fx,1   fx,2)*(lx+1,1   lx+1,2 ' ' lx+1,1,0) = (fx+1,1,fx+1,2)

我们其实只需要求f1,1和f1,2 那么对于一条重链,我们得知了它最下面的点的新权值,我们可以通过把路径上的所有的点的转移矩阵乘上,得到最上面的点的值。因为树剖了,所以这个时候就是线段树派上用场了,注意新编号的大小要由深到浅从小到大,因为修改的时候是不断往上跳的

也就是可以得出一个这样的做法:对于每次修改,先通过该点重链的最下方的点结合新权值更新当前点,再用当前点更新重链头。此后就是重链头更新新的重链尾,重链尾更新他的重链头,不断循环直到根

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

struct node
{
    int x,y,next;
}a[210000];int len,last[110000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct Matrix
{
    int mp[3][3];
    Matrix(){memset(mp,-31,sizeof(mp));}
    Matrix(int A,int B,int C,int D)
    {
        memset(mp,-31,sizeof(mp));
        mp[1][1]=A,mp[1][2]=B,mp[2][1]=C,mp[2][2]=D;
    }
    friend Matrix operator *(Matrix a,Matrix b)
    {
        Matrix c;
        memset(c.mp,-31,sizeof(c.mp));
        for(int i=1;i<=2;i++)
            for(int j=1;j<=2;j++)
                for(int k=1;k<=2;k++)
                    c.mp[i][j]=max(c.mp[i][j],a.mp[i][k]+b.mp[k][j]);
        return c;
    }
}f[110000],g[110000];//当前点答案,转移矩阵 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct trnode//用于求l~r的转移矩阵乘积(带修) 
{
    int l,r,lc,rc;
    Matrix m;
}tr[210000];int trlen;
void tr_bt(int l,int r)
{
    int now=++trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].lc=tr[now].rc=-1;
    tr[now].m=Matrix(0,-(1<<29),-(1<<29),0);
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;tr_bt(l,mid);
        tr[now].rc=trlen+1;tr_bt(mid+1,r);
    }
}
void tr_change(int now,int p,int x)
{
    if(tr[now].l==tr[now].r){tr[now].m=g[x];return ;}
    int mid=(tr[now].l+tr[now].r)/2;
    int lc=tr[now].lc,rc=tr[now].rc;
    if(p<=mid)tr_change(lc,p,x);
    else       tr_change(rc,p,x);
    tr[now].m=tr[lc].m*tr[rc].m;
}
Matrix tr_getmatrix(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r)return tr[now].m;
    int mid=(tr[now].l+tr[now].r)/2;
    int lc=tr[now].lc,rc=tr[now].rc;
         if(r<=mid)  return tr_getmatrix(lc,l,r);
    else if(mid+1<=l)return tr_getmatrix(rc,l,r);
    else return tr_getmatrix(lc,l,mid)*tr_getmatrix(rc,mid+1,r);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//-------------------------------------------------struct----------------------------------------------------------------

int fa[110000],son[110000],tot[110000],dep[110000];
void pre_tree_node(int x)
{
    tot[x]=1,son[x]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x])
        {
            fa[y]=x;
            dep[y]=dep[x]+1;
            pre_tree_node(y);
            if(son[x]==0||tot[son[x]]<tot[y])son[x]=y;
            tot[x]+=tot[y];
        }
    }
}
int z,ys[110000];
int cnt,bel[110000],L[110000],R[110000];
void pre_tree_edge(int x,int wi)
{
    ys[x]=++z;bel[x]=wi;
    if(son[x]!=0)pre_tree_edge(son[x],wi);
    else R[wi]=x;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x]&&y!=son[x])
        {
            L[++cnt]=y;
            pre_tree_edge(y,cnt);
        }
    }
}
void reverse()
{
    for(int i=1;i<=cnt;i++)
    {
        int ll=ys[L[i]],rr=ys[R[i]],now=R[i];
        for(int j=ll;j<=rr;j++)ys[now]=j,now=fa[now];
    }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int w[110000]; 
void dfs(int x)
{
    f[x].mp[1][1]=0,f[x].mp[1][2]=w[x];
    if(son[x]==0)return ;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x])
        {
            dfs(y);
            f[x].mp[1][1]+=max(f[y].mp[1][1],f[y].mp[1][2]);
            f[x].mp[1][2]+=f[y].mp[1][1];
        }
    }
    g[x].mp[1][1]=f[x].mp[1][1]-max(f[son[x]].mp[1][1],f[son[x]].mp[1][2]);
    g[x].mp[2][1]=f[x].mp[1][1]-max(f[son[x]].mp[1][1],f[son[x]].mp[1][2]);
    g[x].mp[1][2]=f[x].mp[1][2]-f[son[x]].mp[1][1];
    g[x].mp[2][2]=-(1<<29);
    tr_change(1,ys[x],x);
}

//-----------------------------------------------------init--------------------------------------------------------------------

Matrix tt;
void update(int y)
{
    while(L[bel[y]]==y&&fa[y]!=0)
    {
        int x=fa[y];
        
        int d1=g[x].mp[1][1],d2=g[x].mp[1][2];
        d1-=max(tt.mp[1][1],tt.mp[1][2]);
        d2-=tt.mp[1][1];
        d1+=max(f[y].mp[1][1],f[y].mp[1][2]);
        d2+=f[y].mp[1][1];
    
        g[x].mp[1][1]=g[x].mp[2][1]=d1;
        g[x].mp[1][2]=d2;
        tr_change(1,ys[x],x);
        
        int u=R[bel[x]];tt=f[x];
        f[x]=f[u]*tr_getmatrix(1,ys[fa[u]],ys[x]);
        
        y=x;
    }
}
void change(int x,int k)
{
    if(L[bel[x]]==x)tt=f[x];
    
    if(son[x]==0)f[x].mp[1][2]+=-w[x]+k;
    else 
    {    
        g[x].mp[1][2]+=-w[x]+k;
        tr_change(1,ys[x],x);
        
        int u=R[bel[x]];
        f[x]=f[u]*tr_getmatrix(1,ys[fa[u]],ys[x]);
    }
    
    if(L[bel[x]]==x)update(x);
    w[x]=k;
}
void solve(int x)
{
    int tx=L[bel[x]];
    while(x!=0)
    {
        if(tx!=x)
        {
            tt=f[tx];
            f[tx]=f[x]*tr_getmatrix(1,ys[fa[x]],ys[tx]);
            update(tx);
        }
        x=fa[tx],tx=L[bel[x]];
    }
}

//----------------------------------------------------solve--------------------------------------------------------------------

int main()
{
    int n,Q,x,y;
    scanf("%d%d",&n,&Q);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        ins(x,y),ins(y,x);
    }
    fa[1]=0,dep[1]=0;pre_tree_node(1);
    z=0,cnt=0,L[1]=1;pre_tree_edge(1,++cnt),reverse();
    trlen=0;tr_bt(1,n);dfs(1);
    
    while(Q--)
    {
        scanf("%d%d",&x,&y);
        change(x,y);solve(x);
        printf("%d
",max(f[1].mp[1][1],f[1].mp[1][2]));
    }
    
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/10000514.html