BZOJ4712 : 洪水
首先不难列出DP方程:
$dp[x]=\min(w[x],h[x])$
$h[x]=\sum dp[son]$
当$w[x]$增加时,显然$dp[x]$不会减少,那么我们求出$dp[x]$的增量$delta$,若$delta=0$那么什么都不需要做。
对于$x$来说,它的$h$值不变。
对于$x$的父亲$y$到某个祖先$z$路径上的所有点来说,它们都满足$h[i]+delta\leq w[i]$,那么这些点的$h$值都要加上$delta$。
对于$u=father[z]$来说,这个点的$h$值也要加上$delta$,但是要重新计算DP值。
这将形成一个循环的过程,不断对$h$数组进行修正即可。
为了得到$z$,需要沿着重链往上爬,对于每条重链在线段树中二分查找。
如果一个区间内$\min(w[i]-h[i])\geq delta$,那么整段区间都可行。
因此在线段树上每个点维护两个值:
$val$:$\min(w[i]-h[i])$
$tag$:区间内所有点$h$值要加上多少
对于叶子节点来说,$tag$实际上就是$h$值,因此不需要额外维护$h$值。
一个点要重新计算DP值,当且仅当它的孩子的总代价超过了自己本身的$w$,并且一旦超过,在下次修改这个点的$w$之前DP值将一直是$w$。
因此每个点一开始会贡献一个可能的重新计算次数,每次修改也会贡献一个。
而暴力修改的次数不会超过所有操作贡献的可能导致暴力的次数,所以暴力次数为$O(n+m)$。
总时间复杂度$O((n+m)\log^2n)$。
#include<cstdio>
typedef long long ll;
const int N=200010,M=524300;
const ll inf=1LL<<60;
char op;
int n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
int f[N],size[N],son[N],top[N],loc[N],q[N],dfn;
ll w[N],z,dp[N],h[N],val[M],tag[M];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void read(ll&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
inline ll min(ll a,ll b){return a<b?a:b;}
void dfs(int x){
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
f[v[i]]=x;
dfs(v[i]);
size[x]+=size[v[i]];
h[x]+=dp[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
if(size[x]==1)h[x]=inf;
dp[x]=min(w[x],h[x]);
}
void dfs2(int x,int y){
q[loc[x]=++dfn]=x;top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
}
inline void tag1(int x,ll p){val[x]-=p;tag[x]+=p;}
inline void pb(int x){if(tag[x])tag1(x<<1,tag[x]),tag1(x<<1|1,tag[x]),tag[x]=0;}
inline void up(int x){val[x]=min(val[x<<1],val[x<<1|1]);}
void build(int x,int a,int b){
if(a==b){
int y=q[a];
val[x]=w[y]-h[y];
tag[x]=h[y];
return;
}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
up(x);
}
ll ask(int x,int a,int b,int c){
if(a==b)return tag[x];
pb(x);
int mid=(a+b)>>1;
return c<=mid?ask(x<<1,a,mid,c):ask(x<<1|1,mid+1,b,c);
}
void changew(int x,int a,int b,int c){
if(a==b){val[x]=w[q[a]]-tag[x];return;}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)changew(x<<1,a,mid,c);else changew(x<<1|1,mid+1,b,c);
up(x);
}
void changeh(int x,int a,int b,int c,int d,ll p){
if(c<=a&&b<=d){tag1(x,p);return;}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)changeh(x<<1,a,mid,c,d,p);
if(d>mid)changeh(x<<1|1,mid+1,b,c,d,p);
up(x);
}
int get(int x,int a,int b,int c,int d,ll p){
if(c<=a&&b<=d){
if(val[x]>=p)return a;
if(a==b)return 0;
}
pb(x);
int mid=(a+b)>>1,t;
if(d<=mid)return get(x<<1,a,mid,c,d,p);
if(c>mid)return get(x<<1|1,mid+1,b,c,d,p);
t=get(x<<1|1,mid+1,b,c,d,p);
if(!t||t>mid+1)return t;
t=get(x<<1,a,mid,c,d,p);
return t?t:mid+1;
}
inline ll DP(int x){return min(w[x],ask(1,1,n,loc[x]));}
inline int gety(int x,ll p){
int t=x;x=f[x];
while(x){
int o=get(1,1,n,loc[top[x]],loc[x],p);
if(!o)break;
if(o>loc[top[x]])return q[o];
t=top[x];
x=f[t];
}
return t;
}
inline void chain(int x,int y,ll p){
while(top[x]!=top[y])changeh(1,1,n,loc[top[x]],loc[x],p),x=f[top[x]];
changeh(1,1,n,loc[y],loc[x],p);
}
inline void modify(int x,ll y){
ll t=DP(x);
w[x]+=y;
changew(1,1,n,loc[x]);
ll d=DP(x)-t;
if(!d)return;
while(f[x]){
int y=gety(x,d);
if(x!=y)chain(f[x],y,d);
x=f[y];
if(!x)return;
t=DP(x);
chain(x,x,d);
d=DP(x)-t;
if(!d)return;
}
}
int main(){
read(n);
for(i=1;i<=n;i++)read(w[i]);
for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
dfs(1);dfs2(1,1);
build(1,1,n);
read(m);
while(m--){
while((op=getchar())!='Q'&&op!='C');read(x);
if(op=='Q')printf("%lld\n",DP(x));else read(z),modify(x,z);
}
return 0;
}
BZOJ4712 : 洪水的更多相关文章
- [bzoj4712]洪水_动态dp
洪水 bzoj-4712 题目大意:给定一棵$n$个节点的有根树.每次询问以一棵节点为根的子树内,选取一些节点使得这个被询问的节点包含的叶子节点都有一个父亲被选中,求最小权值.支持单点修改. 注释:$ ...
- BZOJ4712洪水——动态DP+树链剖分+线段树
题目描述 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬山堵水.那么 ...
- 2018.10.12 bzoj4712: 洪水(树链剖分)
传送门 树链剖分好题. 考虑分开维护重儿子和轻儿子的信息. 令f[i]f[i]f[i]表示iii为根子树的最优值,h[i]h[i]h[i]表示iii重儿子的最优值,g[i]g[i]g[i]表示iii所 ...
- [bzoj4712]洪水 线段树+树链剖分维护动态dp+二分
Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬 ...
- [BZOJ4712]洪水-[树链剖分+线段树]
Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬 ...
- [bzoj4712] 洪水 [树链剖分+线段树+dp]
题面 传送门 思路 DP方程 首先,这题如果没有修改操作就是sb题,dp方程如下 $dp[u]=max(v[u],max(dp[v]))$,其中$v$是$u$的儿子 我们令$g[u]=max(dp[v ...
- BZOJ4712: 洪水(树链剖分维护Dp)
Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地 ...
- bzoj4712 洪水(动态dp)
看起来很模板的一个题啊 qwq 但是我还是wei 题目要求的是一个把根节点和所有叶子断开连接的最小花费. 还是想一个比较\(naive\)的做法 我们令\(dp1[i]\)表示,在\(i\)的子树内, ...
- 动态 DP 学习笔记
不得不承认,去年提高组 D2T3 对动态 DP 起到了良好的普及效果. 动态 DP 主要用于解决一类问题.这类问题一般原本都是较为简单的树上 DP 问题,但是被套上了丧心病狂的修改点权的操作.举个例子 ...
随机推荐
- AE开发实现GP工具IDW
IDW——空间插值 IDW(Inverse Distance Weighted)是一种常用而简便的空间插值方法,它以插值点与样本点间的距离为权重进行加权平均,离插值点越近的样本点赋予的权重越大. 设平 ...
- NAT穿越
1.NAT类型 目前主要的NAT类型有如下几种: 1)Full-cone NAT, also known as one-to-one NAT 一旦一个内网地址 (iAddr:iPort) 被映射到一个 ...
- Python之路【第十九篇】自定义分页实现(模块化)
自定义分页 1.目的&环境准备 目的把分页写成一个模块的方式然后在需要分页的地方直接调用模块就行了. 环境准备Django中生成一个APP并且注册,配置URL&Views 配置URL ...
- 深入理解javascript原型和闭包(15)——闭包
前面提到的上下文环境和作用域的知识,除了了解这些知识之外,还是理解闭包的基础. 至于“闭包”这个词的概念的文字描述,确实不好解释,我看过很多遍,但是现在还是记不住. 但是你只需要知道应用的两种情况即可 ...
- [Network] HTML、XML和JSON学习汇总
写在前面:楼主也是刚刚接触这方面的知识,之前完全是零基础,后来经朋友推荐了几个不错的博文,看完以后豁然开朗.但是此博文更加偏重于基础知识介绍(其实更深的楼主也还不了解,这方面的大神请绕道),只是分享个 ...
- bowtie1和bowtie2的比较
1.对于长度大于50bp的reads,bowtie2更精确:而小于50bp的reads,bowtie1更精确更快速 2.bowtie2支持的reads长度没有上限,当然reads长度在50~1000b ...
- AssetBundle loading failed because.....已解决
http://blog.csdn.net/ldghd/article/details/9632455 ***************************** 一 ******* ...
- espcms列表页ajax无限加载
类似百度图片的效果,滚动到底部后,点击加载更多,加载出第二页,第三页... 替代了传统的上一页,下一页,第几页,以达到在某些情况下使得用户体验更好. 二次开发方法: 1.先在模板文件中增加ajax文件 ...
- android studio--百度定位集成001
安卓现在的大趋势已经是普遍使用androidstudio(安装包[https://yunpan.cn/ckc54idj3JVJb 访问密码 664f])了.这个是集成的一个好的环境. 今天来搞个百度 ...
- mysql锁SELECT FOR UPDATE【转】
MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE ...