【洛谷P4719】动态dp 动态dp模板
题目大意:给你一颗$n$个点的树,点有点权,有$m$次操作,每次操作给定$x$,$y$,表示修改点$x$的权值为$y$。
你需要在每次操作之后求出这棵树的最大权独立集的权值大小。
数据范围:$n,m≤1e5$
我们显然可以得出一个$O(nm)$的暴力做法,每次修改完后$dp$一次,然而这个显然会超时。
考虑当树退化成链时的简单做法。
我们用线段树维护每个区间的答案。对于区间$[l,r]$,我们维护一个$2×2$的答案矩阵$ans$。
设$ans[0][0]$表示区间左端点可能被选择,右端点一定不被选择时的最大值。
设$ans[0][1]$表示区间左端点可能被选择,右端点可能被选择时的最大值。
设$ans[1][0]$表示区间左端点一定不被选择,右端点一定不被选择时的最大值。
设$ans[1][1]$表示区间左端点一定不被选择,右端点可能被选择时的最大值。
对于叶节点,显然$ans[0][0]=ans[0][1]=0$,$ans[1][0]=val[x]$,$ans[1][1]=-INF$。
考虑已经求出$[l,mid]$,$[mid+1,r]$两个区间的答案,如何合并出$[l,r]$的答案。
不难发现$ans[0][0]=max(ansl[0][0]+ansr[0][0],ansl[0][1]+ansr[1][0])$;
$ans[0][1],ans[1][0],ans[1][1]$的转移都长得差不多。
每次修改一个权值,我们可以通过$pushup$更新区间的答案矩阵。
考虑把这个做法扩展到树上,我们通过树链剖分将整棵树剖成若干条链,对于每一条链我们就用如上所述的方式进行维护。对于接有轻儿子的链上节点,我们将轻儿子产生的共吸纳累计,将其加到链上节点上即可。
(细节可以看代码)
时间复杂度:$O(m log^2n)$。
#include<bits/stdc++.h>
#define ls (x<<1)
#define rs (x<<1|1)
#define mid ((a[x].l+a[x].r)>>1)
#define L long long
#define INF 1000000007
#define M 100005
using namespace std; struct edge{int u,next;}e[M*]={}; int head[M]={},use=;
void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
int val[M]={},n,m,f[M][]={}; int siz[M]={},son[M]={},dn[M]={},top[M]={},dfn[M]={},rec[M]={},fa[M]={},t=; void dfs1(int x){
siz[x]=;
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]){
fa[e[i].u]=x;
dfs1(e[i].u);
siz[x]+=siz[e[i].u];
if(siz[son[x]]<siz[e[i].u]) son[x]=e[i].u;
}
}
void dfs2(int x,int Top){
top[x]=Top; dfn[x]=++t; rec[t]=x;
if(son[x]) dfs2(son[x],Top),dn[x]=dn[son[x]];
else dn[x]=x;
for(int i=head[x];i;i=e[i].next)
if(e[i].u!=fa[x]&&e[i].u!=son[x])
dfs2(e[i].u,e[i].u);
}
void dp(int x,int fa){
f[x][]=val[x];
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
dp(e[i].u,x);
f[x][]+=max(f[e[i].u][],f[e[i].u][]);
f[x][]+=f[e[i].u][];
}
} struct mat{
int a[][]; mat(){memset(a,,sizeof(a));}
mat(int x){a[][]=a[][]=a[][]=a[][]=x;}
mat(int a1,int a2,int a3,int a4){a[][]=a1; a[][]=a2; a[][]=a3; a[][]=a4;}
friend mat operator *(mat a,mat b){
mat c=-INF;
for(int i=;i<;i++)
for(int j=;j<;j++)
for(int k=;k<;k++)
c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
return c;
}
}wei[M];
struct seg{int l,r;mat a;}a[M<<];
void pushup(int x){a[x].a=a[ls].a*a[rs].a;} void build(int x,int l,int r){
a[x].l=l; a[x].r=r;
if(l==r){
int u=rec[l],g0=,g1=val[u];
for(int i=head[u];i;i=e[i].next)
if(e[i].u!=son[u]&&e[i].u!=fa[u]){
g0+=max(f[e[i].u][],f[e[i].u][]);
g1+=f[e[i].u][];
}
a[x].a=wei[l]=mat(g0,g0,g1,-INF);
return;
}
build(ls,l,mid);
build(rs,mid+,r);
pushup(x);
}
void updata(int x,int k){
if(a[x].l==a[x].r) return void(a[x].a=wei[k]);
if(k<=mid) updata(ls,k);
else updata(rs,k);
pushup(x);
} mat query(int x,int l,int r){
if(l<=a[x].l&&a[x].r<=r) return a[x].a;
mat res;
if(l<=mid) res=query(ls,l,r);
if(mid<r){
if(l<=mid) return res*query(rs,l,r);
return query(rs,l,r);
}else return res;
}
mat query(int x){return query(,dfn[top[x]],dfn[dn[x]]);}
void solve(){mat hh=query(); printf("%d\n",max(hh.a[][],hh.a[][]));} void Updata(int x,int Val){
wei[dfn[x]].a[][]+=Val-val[x]; val[x]=Val;
while(x){ mat last=query(x);
int lg0=max(last.a[][],last.a[][]),lg1=last.a[][]; updata(,dfn[x]); mat now=query(x);
int ng0=max(now.a[][],now.a[][]),ng1=now.a[][]; x=fa[top[x]]; if(!x) return; int g0=ng0-lg0,g1=ng1-lg1;
wei[dfn[x]].a[][]+=g0;
wei[dfn[x]].a[][]+=g0;
wei[dfn[x]].a[][]+=g1;
}
} int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",val+i);
for(int i=,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs1();
dfs2(,);
dp(,);
build(,,n);
//solve();
while(m--){
int x,y; scanf("%d%d",&x,&y);
Updata(x,y);
solve();
}
}
【洛谷P4719】动态dp 动态dp模板的更多相关文章
- 洛谷 P5279 - [ZJOI2019]麻将(dp 套 dp)
洛谷题面传送门 一道 dp 套 dp 的 immortal tea 首先考虑如何判断一套牌是否已经胡牌了,考虑 \(dp\).我们考虑将所有牌按权值大小从大到小排成一列,那我们设 \(dp_ ...
- 洛谷P4719 【模板】"动态 DP"&动态树分治
[模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...
- 洛谷p1052过河 路径压缩+dp
洛谷 P1052 过河 思路部分可以看这篇博客 我将在这里对其进行一些解释与补充 首先我们先看题 乍一看 这不是模板题吗 然后开开心心的敲了一个简单dp上去 #include<iostream& ...
- 洛谷2344 奶牛抗议(DP+BIT+离散化)
洛谷2344 奶牛抗议 本题地址:http://www.luogu.org/problem/show?pid=2344 题目背景 Generic Cow Protests, 2011 Feb 题目描述 ...
- Lightning Conductor 洛谷P3515 决策单调性优化DP
遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...
- 洛谷P1541 乌龟棋(四维DP)
To 洛谷.1541 乌龟棋 题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游 ...
- 【洛谷】P1052 过河【DP+路径压缩】
P1052 过河 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙 ...
- 【题解】洛谷P1052 [NOIP2005TG] 过河(DP+离散化)
题目来源:洛谷P1052 思路 一开始觉得是贪心 但是仔细一想不对 是DP 再仔细一看数据不对 有点大 如果直接存下的话 显然会炸 那么就需要考虑离散化 因为一步最大跳10格 那么我们考虑从1到10都 ...
- 洛谷1736(二维dp+预处理)
洛谷1387的进阶版,但很像. 1387要求是“全为1的正方形”,取dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]))吧?这个有“只有对 ...
- bzoj3295 洛谷P3157、1393 动态逆序对——树套树
题目:bzoj3295 https://www.lydsy.com/JudgeOnline/problem.php?id=3295 洛谷 P3157(同一道题) https://www.luogu.o ...
随机推荐
- KBMMW 4.82.00 发布
作者最近加紧了更新进度,赞一个. 时间都去哪儿了? 还没好好看4.81, 新版就来了. 这个版本主要是增强日志管理,已经强大到替换delphi 本身的异常处理了. We are happy to an ...
- 说说wee sing(ZZ)
我自己在当当上买过wee sing,也在网上下了wee sing 的DVD,也借过同事在淘宝上买的Wee sing 套装(9cd + 5DVD).所以对这套资料还是很熟悉的. 淘宝上的套装卖 ...
- JedisPoolConfig解说
版本一 今天发现Jedis 默认的连接方式 jedis=new Jedis(“localhost”,6379),老是发生connection timeout. 后来发现jedis类包还有一种可以设置最 ...
- Linux必须学的东西,鉴于各大公司实际开发都不用Windows系统
Windows安全性比较差,所以各大公司会使用其他的平台,所以像Linux就是很常用的,基于Unix的开源系统,鉴于很多人写的很散,所以自己总结下对于自己有用的重点,现在总结下简单的linxu的命令使 ...
- Windows10+Python3下安装NumPy+SciPy+Matplotlib
Numpy.SciPy.MatplotLib是Python下从事科学计算必不可少的库.我在用其他的方法安装时出现各种问题,发现直接安装.whl包是最快且不报错的方法. 1.下载.whl包在下面的网站中 ...
- _variant_t与其他数据类型的转换
转自:http://kuaixingdong.blog.hexun.com/29627840_d.html 我们先看看COM所支持的一些类型的基本类: (微软提供,在comdef.h中定义) 在COM ...
- hdu5883 The Best Path 2016-09-21 21:31 92人阅读 评论(0) 收藏
The Best Path Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) To ...
- office2010安装不成功提示缺少MSXML 6.10.1129.0?
office2010安装 1. office重装 由于之前重装系统后安装office2010很顺利,这次删除office2010,由于没有删除干净,在程序删除面板中误点删除了其他文件所致,所以在此安装 ...
- POJ1511来回最短路
POJ1511 问你从1到其它点得所有最短路之和 与 其他点到1得所有最短路之和 得总和 思路很明确就是两次最短路,翻转一次地图就好了 一开始就是两次spfa之间处理好数据得更新管理就好 vect ...
- python的特性
python使用c语言开发 1.面向对象的特性 面向对象的程序设计抽象出对象的行为和属性,把行为和属性分离开,但是又合理的组织在一起.它消除了保护类型.抽象类.接口等面向对象的元素,使得面向对象的概念 ...