luogu P4719 【模板】动态dp
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的更多相关文章
- [luogu 4719][模板]动态dp
传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...
- 【洛谷P4719】动态dp 动态dp模板
题目大意:给你一颗$n$个点的树,点有点权,有$m$次操作,每次操作给定$x$,$y$,表示修改点$x$的权值为$y$. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 数据范围:$n,m≤ ...
- [模板] 动态dp
用途 对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值 做法(树剖版) 以最大权独立集为例 设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小 ...
- 洛谷4719 【模板】动态dp
题目:https://www.luogu.org/problemnew/show/P4719 关于动态DP似乎有猫锟的WC2018论文,但找不见:还是算了. http://immortalco.blo ...
- Luogu P4643 【模板】动态dp
题目链接 Luogu P4643 题解 猫锟在WC2018讲的黑科技--动态DP,就是一个画风正常的DP问题再加上一个动态修改操作,就像这道题一样.(这道题也是PPT中的例题) 动态DP的一个套路是把 ...
- 洛谷P4719 【模板】"动态 DP"&动态树分治
[模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...
- 洛谷P4719 【模板】动态dp(ddp LCT)
题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...
- P4719 【模板】动态dp
\(\color{#0066ff}{ 题目描述 }\) 给定一棵\(n\)个点的树,点带点权. 有\(m\)次操作,每次操作给定\(x,y\),表示修改点xx的权值为\(y\). 你需要在每次操作之后 ...
- 洛谷 P4719 【模板】动态dp【动态dp】
是动态dp的板子 大致思想就是用g[u]来表示不包含重链转移的dp值,然后用线段树维护重链,这样线段树的根就相当于这条重链的top的真实dp值 每次修改的时候,修改x点会影响到x到根的真实dp值,但是 ...
- P4719 【模板】"动态 DP"&动态树分治
题目描述 给定一棵 n 个点的树,点带点权. 有 m 次操作,每次操作给定 x,y,表示修改点 x 的权值为 y. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 输入格式 第一行有两个整数 ...
随机推荐
- struts2与常用表格ajax操作的json传值问题
struts与常用的dataTables和jqueryGrid等表格进行ajax传值时,经常会传值不适配的问题,这是因为struts在进行ajax操作时已经对你要操作的json数据进行了处理,所以不需 ...
- 初识 Bootstrap
Bootstrap 概述 Bootstrap 是一个前端框架,使用它可以快速开发响应式页面,还能专门针对 PC 端或移动端快速开发,大大提高了开发效率. Bootstrap 是最受欢迎的 HTML.C ...
- [Python3网络爬虫开发实战] 2.2-网页基础
用浏览器访问网站时,页面各不相同,你有没有想过它为何会呈现这个样子呢?本节中,我们就来了解一下网页的基本组成.结构和节点等内容. 1. 网页的组成 网页可以分为三大部分——HTML.CSS和JavaS ...
- Oracle创建 表空间 用户 给用户授权命令
//创建表空间 create tablespace ACHARTSdatafile 'D:\oradata\orcl\ACHARTS01.DBF' size 800mautoextend on nex ...
- 表情符号Emoji的正则表达式
/** * 判断字符串包含表情 * @param value * @return */ public static boolean containsEmoji(String value){ boole ...
- bzoj 1049 [HAOI2006]数字序列
[bzoj1049][HAOI2006]数字序列 Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不 ...
- [ C语言 ] 迷宫 迷宫生成器 [ 递归与搜索 ]
[原创]转载请注明出处 [浙江大学 程序设计专题] [地图求解器] 本题目要求输入一个迷宫地图,输出从起点到终点的路线. 基本思路是从起点(Sx,Sy)每次枚举该格子上下左右四个方向,直到走到终点(T ...
- 序列终结者(bzoj 1521)
Description 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列 要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这 ...
- Network(poj 3694)
题意:一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(注意是要考虑之前连了的边,每次回答是在上一次的基础之上) /* tarjan+LCA 先用ta ...
- 2018/3/14 Hadoop学习笔记(一)
首先,什么是Hadoop?为什么它是现在大数据处理最热门的框架呢?(正确来说,现在Hadoop是一个生态圈) Hadoop是apache下一套开源的服务框架,它主要的作用就是利用服务器集群,来对海量数 ...