• 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;
    }
  • 相关阅读:
    C++前置声明的几种方式
    C++中看上去有些奇怪的惯用法:int和bool之间的转换
    在线文档生成工具 mkdocs 使用方法
    对Java前四章的感受
    类与对象的学习之路
    201671010133 201620172 《java程序设计》 初学java!
    神奇的位运算及其简单应用
    mysql 和 mongo db 语法对比
    phpMyAdmin 配置
    mongoDB 基础指令
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10000514.html
Copyright © 2020-2023  润新知