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<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std; struct node
{
int x,y,next;
}a[];int len,last[];
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[][];
Matrix(){memset(mp,-,sizeof(mp));}
Matrix(int A,int B,int C,int D)
{
memset(mp,-,sizeof(mp));
mp[][]=A,mp[][]=B,mp[][]=C,mp[][]=D;
}
friend Matrix operator *(Matrix a,Matrix b)
{
Matrix c;
memset(c.mp,-,sizeof(c.mp));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int k=;k<=;k++)
c.mp[i][j]=max(c.mp[i][j],a.mp[i][k]+b.mp[k][j]);
return c;
}
}f[],g[];//当前点答案,转移矩阵
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct trnode//用于求l~r的转移矩阵乘积(带修)
{
int l,r,lc,rc;
Matrix m;
}tr[];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=-;
tr[now].m=Matrix(,-(<<),-(<<),);
if(l<r)
{
int mid=(l+r)/;
tr[now].lc=trlen+;tr_bt(l,mid);
tr[now].rc=trlen+;tr_bt(mid+,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)/;
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)/;
int lc=tr[now].lc,rc=tr[now].rc;
if(r<=mid) return tr_getmatrix(lc,l,r);
else if(mid+<=l)return tr_getmatrix(rc,l,r);
else return tr_getmatrix(lc,l,mid)*tr_getmatrix(rc,mid+,r);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //-------------------------------------------------struct---------------------------------------------------------------- int fa[],son[],tot[],dep[];
void pre_tree_node(int x)
{
tot[x]=,son[x]=;
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]+;
pre_tree_node(y);
if(son[x]==||tot[son[x]]<tot[y])son[x]=y;
tot[x]+=tot[y];
}
}
}
int z,ys[];
int cnt,bel[],L[],R[];
void pre_tree_edge(int x,int wi)
{
ys[x]=++z;bel[x]=wi;
if(son[x]!=)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=;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[];
void dfs(int x)
{
f[x].mp[][]=,f[x].mp[][]=w[x];
if(son[x]==)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[][]+=max(f[y].mp[][],f[y].mp[][]);
f[x].mp[][]+=f[y].mp[][];
}
}
g[x].mp[][]=f[x].mp[][]-max(f[son[x]].mp[][],f[son[x]].mp[][]);
g[x].mp[][]=f[x].mp[][]-max(f[son[x]].mp[][],f[son[x]].mp[][]);
g[x].mp[][]=f[x].mp[][]-f[son[x]].mp[][];
g[x].mp[][]=-(<<);
tr_change(,ys[x],x);
} //-----------------------------------------------------init-------------------------------------------------------------------- Matrix tt;
void update(int y)
{
while(L[bel[y]]==y&&fa[y]!=)
{
int x=fa[y]; int d1=g[x].mp[][],d2=g[x].mp[][];
d1-=max(tt.mp[][],tt.mp[][]);
d2-=tt.mp[][];
d1+=max(f[y].mp[][],f[y].mp[][]);
d2+=f[y].mp[][]; g[x].mp[][]=g[x].mp[][]=d1;
g[x].mp[][]=d2;
tr_change(,ys[x],x); int u=R[bel[x]];tt=f[x];
f[x]=f[u]*tr_getmatrix(,ys[fa[u]],ys[x]); y=x;
}
}
void change(int x,int k)
{
if(L[bel[x]]==x)tt=f[x]; if(son[x]==)f[x].mp[][]+=-w[x]+k;
else
{
g[x].mp[][]+=-w[x]+k;
tr_change(,ys[x],x); int u=R[bel[x]];
f[x]=f[u]*tr_getmatrix(,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!=)
{
if(tx!=x)
{
tt=f[tx];
f[tx]=f[x]*tr_getmatrix(,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=;memset(last,,sizeof(last));
for(int i=;i<=n;i++)scanf("%d",&w[i]);
for(int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
ins(x,y),ins(y,x);
}
fa[]=,dep[]=;pre_tree_node();
z=,cnt=,L[]=;pre_tree_edge(,++cnt),reverse();
trlen=;tr_bt(,n);dfs(); while(Q--)
{
scanf("%d%d",&x,&y);
change(x,y);solve(x);
printf("%d\n",max(f[].mp[][],f[].mp[][]));
} return ;
}

luogu P4719 【模板】动态dp的更多相关文章

  1. [luogu 4719][模板]动态dp

    传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...

  2. 【洛谷P4719】动态dp 动态dp模板

    题目大意:给你一颗$n$个点的树,点有点权,有$m$次操作,每次操作给定$x$,$y$,表示修改点$x$的权值为$y$. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 数据范围:$n,m≤ ...

  3. [模板] 动态dp

    用途 对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值 做法(树剖版) 以最大权独立集为例 设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小 ...

  4. 洛谷4719 【模板】动态dp

    题目:https://www.luogu.org/problemnew/show/P4719 关于动态DP似乎有猫锟的WC2018论文,但找不见:还是算了. http://immortalco.blo ...

  5. Luogu P4643 【模板】动态dp

    题目链接 Luogu P4643 题解 猫锟在WC2018讲的黑科技--动态DP,就是一个画风正常的DP问题再加上一个动态修改操作,就像这道题一样.(这道题也是PPT中的例题) 动态DP的一个套路是把 ...

  6. 洛谷P4719 【模板】"动态 DP"&动态树分治

    [模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...

  7. 洛谷P4719 【模板】动态dp(ddp LCT)

    题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...

  8. P4719 【模板】动态dp

    \(\color{#0066ff}{ 题目描述 }\) 给定一棵\(n\)个点的树,点带点权. 有\(m\)次操作,每次操作给定\(x,y\),表示修改点xx的权值为\(y\). 你需要在每次操作之后 ...

  9. 洛谷 P4719 【模板】动态dp【动态dp】

    是动态dp的板子 大致思想就是用g[u]来表示不包含重链转移的dp值,然后用线段树维护重链,这样线段树的根就相当于这条重链的top的真实dp值 每次修改的时候,修改x点会影响到x到根的真实dp值,但是 ...

  10. P4719 【模板】"动态 DP"&动态树分治

    题目描述 给定一棵 n 个点的树,点带点权. 有 m 次操作,每次操作给定 x,y,表示修改点 x 的权值为 y. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 输入格式 第一行有两个整数 ...

随机推荐

  1. Servlet中的几个重要的对象(转)

    讲解四大类,ServletConfig对象,ServletContext对象.request对象,response对象 ServletConfig对象 获取途径:getServletConfig(); ...

  2. Hadoop-2.7.1伪分布--安装配置hbase 1.1.2

    hbase-1.1.2下载地址:http://www.eu.apache.org/dist/hbase/stable/hbase-1.1.2-bin.tar.gz 下载之后解压至\usr\local目 ...

  3. html页面加载初始化方法

    js: 方法一: window.onload=function(){内容} 方法二(自己定义方法): function onload(){内容} onload(); jQuery: 方法一: $(do ...

  4. RNN与情感分类问题实战-加载IMDB数据集

    目录 Sentiment Analysis Two approaches Single layer Multi-layers Sentiment Analysis Two approaches Sim ...

  5. 使用java发送电子邮件

    经常在账号绑定邮箱或找回密码时,邮箱会收到一条验证邮件,好奇用代码该怎么发送邮件,看到了许多相关的博客,实现步骤都写的很详细,今天照着其他博客的步骤也确实实现了代码发送邮件,在这里重新记录下步骤,加深 ...

  6. STM32F407 开发环境搭建 程序下载 个人笔记

    详细资料: http://www.openedv.com/thread-13912-1-1.html 需要安装的软件: 1.keil(MDK,必选),用keygen破解 2.CH340驱动,(usb串 ...

  7. servlet页面没有跳转

    Boolean b = userService.selectByParams(user);if (b) { req.getSession().setAttribute("loginname& ...

  8. 九度oj 题目1055:数组逆置

    题目1055:数组逆置 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:8225 解决:3932 题目描述: 输入一个字符串,长度小于等于200,然后将数组逆置输出. 输入: 测试数据有多组 ...

  9. [K/3Cloud] 理解BOS关于Enabled属性的表决器原理

    通常的编程中,我们习惯: btnOK.Enabled = true; 这个样子就会将按钮变成有效,反之亦然.但在ERP的表单中,其某个按钮或字段其有效性及其复杂,例如一个表格中某个数量单元格其有效性是 ...

  10. 关于android系统启动不同activity默认过渡动画不同的一些认识

    在同一个android设备里,发现不同的app启动时显示的过渡动画是不同的.查看显示不同过渡动画的两个app的源码,其设置的主题都是同一个主题,但是为什么过渡动画效果不同呢?后来发现,activity ...