zoukankan      html  css  js  c++  java
  • luogu P4719 【模板】动态 DP (LCT版)

    方法二:LCT+矩阵乘法

    上文中,我们用线段树来维护重链上的各种矩阵转移.

    第二种方法是将树链剖分替换为动态树.

    我们知道,矩阵乘法 $egin{bmatrix} F_{u,0} & F_{u,0}\ F_{u,1}  & -infty end{bmatrix} imesegin{bmatrix} F_{i,0}\F_{i,1} end{bmatrix}=egin{bmatrix} F_{u,0}\F_{u,1} end{bmatrix}$ 中第一个矩阵中的每一个 $F_{u,k}$ 都是指考虑轻链时 $u$ 的 DP 值.

    在 $LCT$ 中,树的轻重路径是交替变换的.

    我们用维护子树信息的方式维护即可.

    即设 $tmp$ 矩阵表示该点虚儿子的所有 DP 值的贡献(只是不包括重儿子).

    再设 $t$ 矩阵维护 $Splay$ 中的转移.

    具体细节看看代码:
     

    Code:

    // luogu-judger-enable-o2
    //Dynamic DP with LCT 
    #include<bits/stdc++.h>
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin)  
    #define maxn 100002 
    #define inf 100000000 
    using namespace std; 
    //Link cut tree
    void de()
    {
        printf("ok
    "); 
    }
    namespace LCT
    {     
    
        struct Matrix
        {
            ll a[2][2];
            ll*operator[](int x){ return a[x];}    
        }t[maxn],tmp[maxn];  
        Matrix operator*(Matrix a,Matrix b)
        {
        	Matrix c;
        	c[0][0]=max(a[0][0]+b[0][0],a[0][1]+b[1][0]); 
        	c[0][1]=max(a[0][0]+b[0][1],a[0][1]+b[1][1]); 
        	c[1][0]=max(a[1][0]+b[0][0],a[1][1]+b[1][0]); 
        	c[1][1]=max(a[1][0]+b[0][1],a[1][1]+b[1][1]); 
        	return c; 
        }
    
        //tmp :: 虚儿子信息 
        //t :: 树剖实际转移矩阵 
        #define lson ch[x][0]
        #define rson ch[x][1] 
        int ch[maxn][2],f[maxn]; 
        int isRoot(int x) 
        {	
            return !(ch[f[x]][0]==x || ch[f[x]][1]==x);  
        }
        int get(int x) 
        { 
            return ch[f[x]][1]==x; 
        } 
        void pushup(int x)
        { 
            t[x]=tmp[x]; 
            if(lson) t[x]=t[lson]*t[x]; 
            if(rson) t[x]=t[x]*t[rson]; 
        }
        void rotate(int x)
        {
            int old=f[x],fold=f[old],which=get(x); 
            if(!isRoot(old)) ch[fold][ch[fold][1]==old]=x; 
            ch[old][which]=ch[x][which^1],f[ch[old][which]]=old; 
            ch[x][which^1]=old,f[old]=x,f[x]=fold; 
            pushup(old),pushup(x); 
        }
        void splay(int x) 
        {
            int u=x;
            while(!isRoot(u)) u=f[u];                     
            u=f[u]; 
            for(int fa;(fa=f[x])!=u;rotate(x)) 
                if(f[fa]!=u) rotate(get(fa)==get(x)?fa:x);  
        }
        void Access(int x)
        {
            for(int y=0;x;y=x,x=f[x])
            {
                splay(x); 
                if(rson) 
                {
                    tmp[x][0][0]+=max(t[rson][0][0],t[rson][1][0]); 
                    tmp[x][1][0]+=t[rson][0][0];     
                }
                if(y) 
                { 
                    tmp[x][0][0]-=max(t[y][0][0],t[y][1][0]); 
                    tmp[x][1][0]-=t[y][0][0];  
                }
                tmp[x][0][1]=tmp[x][0][0];  
                rson=y,pushup(x); 
            }
        } 
    };     
    
    
    //variables 
    int DP[maxn][2];   
    int V[maxn],hd[maxn],to[maxn<<1],nex[maxn<<1]; 
    int n,Q,edges; 
    void add(int u,int v){ nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  } 
    
    
    //build graph 
    void dfs(int u,int ff)
    {         
        LCT::f[u]=ff; 
        DP[u][0]=0;
        DP[u][1]=V[u]; 
        for(int i=hd[u];i;i=nex[i])
        {
            int v=to[i]; 
            if(v==ff) continue; 
            dfs(v,u); 
            DP[u][0]+=max(DP[v][1],DP[v][0]); 
            DP[u][1]+=DP[v][0]; 
        }            
        LCT::tmp[u]=(LCT::Matrix){ DP[u][0], DP[u][0], DP[u][1], -inf};
        LCT::t[u]=LCT::tmp[u];   
    }
    
    
    //主程序~ 
    int main()
    {
        // setIO("input");  
        scanf("%d%d",&n,&Q); 
        for(int i=1;i<=n;++i) scanf("%d",&V[i]); 
        for(int i=1,u,v;i<n;++i) 
        {
            scanf("%d%d",&u,&v); 
            add(u,v),add(v,u); 
        }
        dfs(1,0); 
        while(Q--)
        {
            int x,y; 
            scanf("%d%d",&x,&y);            
            LCT::Access(x);
            LCT::splay(x);                
            LCT::tmp[x][1][0]+=(ll)y-V[x];
            V[x]=y;        
            LCT::pushup(x);    
            LCT::splay(1); 
            printf("%lld
    ",max(LCT::t[1][0][0], LCT::t[1][1][0]));       
        }
        return 0; 
    }
    

      

  • 相关阅读:
    RecyclerView的万能适配器+定义可以到底部自动刷新的RecyclerView
    Material Design 摘要
    模版方法模式
    工厂方法模式
    单例模式
    Android中使用Intent和IntentFilter进行通信
    Json/XML/HTML数据解析
    Java中集合总结
    重构笔记
    Android中ActionBar的使用
  • 原文地址:https://www.cnblogs.com/guangheli/p/10971324.html
Copyright © 2011-2022 走看看