【BZOJ4712】洪水
题解:
注意题目说了每个点的权值只能增加
每个点的dp方程比较简单 min(v[i],sum[i])
那么我们考虑如果v[i]增加那么上面使用sum[i]的会带来影响
暴力的做就是一个个往上查然后修改
比较显然的是这个东西可以二分
我们维护v[i]-sum[i]的值,查到那个不符合的就可以了
这样我们就变成了花log^2n的时间对v[i]>sum[i]的变成v[i]<sum[i]
而每次操作最多增加一个v[i]>sum[i]
所以复杂度是对的
树链剖分维护,复杂度nlog^2n
还是比较考验代码能力的
树剖那里一定要理清楚思路
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rint register ll
#define rll register ll
#define IL inline
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
const ll N=2e5+1e4;
const ll N2=N*;
const ll INF=1e9;
ll n,m,v[N],head[N],id[N],rel[N],yz[N],fa[N],f[N],son[N],g[N],num[N],top[N],l;
ll data[N2],cnt,lazy[N2];
struct re{
ll a,b,c;
}e[N*];
void arr(ll x,ll y)
{
e[++l].a=head[x];
e[l].b=y;
head[x]=l;
}
void dfs(ll x,ll y)
{
f[x]=v[x]; num[x]=; fa[x]=y;
ll sum=;
for (rint u=head[x];u;u=e[u].a)
{
rint v=e[u].b;
if (v!=y)
{
yz[x]=;
dfs(v,x);
sum+=f[v];
num[x]+=num[v];
if (num[v]>num[son[x]]) son[x]=v;
}
}
if (sum) f[x]=min(f[x],sum);
if (sum) g[x]=sum; else g[x]=f[x];
}
void dfs2(ll x,ll y,ll z)
{
id[x]=++cnt; rel[cnt]=x;
top[x]=y;
if (!son[x]) return;
dfs2(son[x],y,x);
for (rint u=head[x];u;u=e[u].a)
{
rint v=e[u].b;
if (v!=z&&v!=son[x]) dfs2(v,v,x);
}
}
#define updata(x) data[x]=min(data[x*2],data[x*2+1])
#define mid ((h+t)/2)
IL void down(ll x)
{
if (!lazy[x]) return;
lazy[x*]+=lazy[x]; lazy[x*+]+=lazy[x];
data[x*]-=lazy[x]; data[x*+]-=lazy[x];
lazy[x]=;
}
void build(ll x,ll h,ll t)
{
if (h==t)
{
data[x]=v[rel[h]]-g[rel[h]];
return;
}
build(x*,h,mid); build(x*+,mid+,t);
updata(x);
}
ll query(ll x,ll h,ll t,ll pos)
{
if (h==t)
{
if (data[x]>) return(v[rel[h]]-data[x]);
else return(v[rel[h]]);
}
down(x);
if (pos<=mid) return(query(x*,h,mid,pos));
else return(query(x*+,mid+,t,pos));
updata(x);
}
void change2(ll x,ll h,ll t,ll h1,ll t1,ll k)
{
if (h1<=h&&t<=t1)
{
lazy[x]+=k; data[x]-=k; return;
}
down(x);
if (h1<=mid) change2(x*,h,mid,h1,t1,k);
if (mid<t1) change2(x*+,mid+,t,h1,t1,k);
updata(x);
}
ll query2(ll x,ll h,ll t,ll h1,ll t1)
{
if (h1<=h&&t<=t1)
{
return(data[x]);
}
down(x);
ll ans=INF;
if (h1<=mid) ans=min(ans,query2(x*,h,mid,h1,t1));
if (mid<t1) ans=min(ans,query2(x*+,mid+,t,h1,t1));
return(ans);
}
vector<re> ve;
void find2(ll x,ll h,ll t,ll h1,ll t1)
{
if (h1<=h&&t<=t1)
{
ve.push_back((re){x,h,t}); return;
}
down(x);
if (h1<=mid) find2(x*,h,mid,h1,t1);
if (mid<t1) find2(x*+,mid+,t,h1,t1);
}
ll find3(ll x,ll h,ll t,ll k)
{
if (h==t) return(h);
down(x);
if (data[x*+]<k) return(find3(x*+,mid+,t,k));
else return(find3(x*,h,mid,k));
}
void change(rll x,rll y)
{
if (!y) return;
rll now=x;
while (top[now])
{
if (query2(,,n,id[top[now]],id[now])>=y)
{
change2(,,n,id[top[now]],id[now],y); //v[x]-g[x] 减小y
} else
{
ve.clear();
find2(,,n,id[top[now]],id[now]);
rll l=int(ve.size())-;
rll k;
dep(i,l,)
if (data[ve[i].a]<y)
{
k=find3(ve[i].a,ve[i].b,ve[i].c,y); // k.a 位置 k.b v[x]-g[x]
break;
}
rll x1=query(,,n,k);
change2(,,n,k,id[now],y);
rll x2=query(,,n,k);
change(fa[rel[k]],x2-x1);
break;
}
now=fa[top[now]];
}
}
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
ios::sync_with_stdio(false);
cin>>n;
rep(i,,n) cin>>v[i];
rep(i,,n-)
{
ll x,y; cin>>x>>y;
arr(x,y); arr(y,x);
}
dfs(,);
dfs2(,,);
build(,,n);
cin>>m;
char cc;
rep(i,,m)
{
ll x,y;
cin>>cc;
if (cc=='Q')
{
cin>>x;
cout<<query(,,n,id[x])<<endl;
} else
{
cin>>x>>y;
ll x1=query(,,n,id[x]);
v[x]+=y;
if (yz[x])
{
change2(,,n,id[x],id[x],-y);
ll x3=query(,,n,id[x]);
if (x3>x1) change(fa[x],x3-x1);
}
else change(fa[x],y);
}
}
return ;
}
【BZOJ4712】洪水的更多相关文章
- [bzoj4712]洪水_动态dp
洪水 bzoj-4712 题目大意:给定一棵$n$个节点的有根树.每次询问以一棵节点为根的子树内,选取一些节点使得这个被询问的节点包含的叶子节点都有一个父亲被选中,求最小权值.支持单点修改. 注释:$ ...
- BZOJ4712 : 洪水
首先不难列出DP方程: $dp[x]=\min(w[x],h[x])$ $h[x]=\sum dp[son]$ 当$w[x]$增加时,显然$dp[x]$不会减少,那么我们求出$dp[x]$的增量$de ...
- 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 问题,但是被套上了丧心病狂的修改点权的操作.举个例子 ...
随机推荐
- OpenStack实践系列②认证服务Keystone
OpenStack实践系列②认证服务Keystone 三.实战OpenStack之控制节点3.1 CentOS7的时间同步服务器chrony 下载chrony # yum install -y chr ...
- 关于在Fragment中设置toolbar及菜单的方法
在NoActionBar的主题中onCreateOptionsMenu方法不会运行,这里就需要将toolbar强制转换为ActionBar 在加入toolbar的监听之类后需要在onCreateVie ...
- how to avoid inheritance abuse
Liskov Principle: if S is a subtype of Type T, then any objects of type T may be repalced by objects ...
- python中__init__ ,__del__ &__new__
__new__ __new__方法是用来创建对象,__new__方法需要有一个返回值,这个返回值表示创建出来的对象的引用 __init__ __init__方法在类的一个对象被建立时 ,马上执行.__ ...
- SpringBoot和SpringCloud面试题
一. 什么是springboot 1.用来简化spring应用的初始搭建以及开发过程 使用特定的方式来进行配置(properties或yml文件) 2.创建独立的spring引用程序 main方法运行 ...
- VBS计时器
用VBS实现一个以分钟为单位的计时器: rem msgbox now 'now is the system para msgbox "Timer",,"CreatedBy ...
- ACM-ICPC 2018 焦作赛区网络预赛 G Give Candies
There are NNN children in kindergarten. Miss Li bought them NNN candies. To make the process more in ...
- ajax控件无法使用 iis配置及web修改(转载)
1.Web.config配置问题:将Web.config中的相关节配置成如下,然后重新编译你的程序:<httpHandlers><remove verb="*" ...
- oracle提高查询效率的34条方法
注:本文来源:远方的守望者 <oracle提高查询效率的34条方法> oracle提高查询效率的34条方法 1.选择最有效率的表名顺序 (只在基于规则的优化器中有效): ORACLE的解 ...
- Confluence 6 缓存性能示例
有关 Confluence 的缓存性能如何设置,让我们看看下面的表: 缓存(Caches) % 使用的缓存(Used) % 有效率(Effectiveness) 对象/大小(Objects/Size) ...