热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

luoguP4719【模板】动态dp

noip怎么考这种东西啊。。。看错题场上爆零凉了首先我们先进行树链剖分,那么问题可以转换成重链的答案+其他子节点的答案而每次修改相当于改一段重链的答案,改一次其他子节点的答案交替进行这样只

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

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

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

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

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

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

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

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

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

#include
#include
#include
#include
#include
#include
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]]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)
    {
        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\n",max(f[1].mp[1][1],f[1].mp[1][2]));
    }
    
    return 0;
}

 


推荐阅读
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 实现一个通讯录系统,可添加、删除、修改、查找、显示、清空、排序通讯录信息
    本文介绍了如何实现一个通讯录系统,该系统可以实现添加、删除、修改、查找、显示、清空、排序通讯录信息的功能。通过定义结构体LINK和PEOPLE来存储通讯录信息,使用相关函数来实现各项功能。详细介绍了每个功能的实现方法。 ... [详细]
author-avatar
炜一爱妮
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有