题解:

注意题目说了每个点的权值只能增加

每个点的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】洪水的更多相关文章

  1. [bzoj4712]洪水_动态dp

    洪水 bzoj-4712 题目大意:给定一棵$n$个节点的有根树.每次询问以一棵节点为根的子树内,选取一些节点使得这个被询问的节点包含的叶子节点都有一个父亲被选中,求最小权值.支持单点修改. 注释:$ ...

  2. BZOJ4712 : 洪水

    首先不难列出DP方程: $dp[x]=\min(w[x],h[x])$ $h[x]=\sum dp[son]$ 当$w[x]$增加时,显然$dp[x]$不会减少,那么我们求出$dp[x]$的增量$de ...

  3. BZOJ4712洪水——动态DP+树链剖分+线段树

    题目描述 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬山堵水.那么 ...

  4. 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所 ...

  5. [bzoj4712]洪水 线段树+树链剖分维护动态dp+二分

    Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬 ...

  6. [BZOJ4712]洪水-[树链剖分+线段树]

    Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬 ...

  7. [bzoj4712] 洪水 [树链剖分+线段树+dp]

    题面 传送门 思路 DP方程 首先,这题如果没有修改操作就是sb题,dp方程如下 $dp[u]=max(v[u],max(dp[v]))$,其中$v$是$u$的儿子 我们令$g[u]=max(dp[v ...

  8. BZOJ4712: 洪水(树链剖分维护Dp)

    Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地 ...

  9. bzoj4712 洪水(动态dp)

    看起来很模板的一个题啊 qwq 但是我还是wei 题目要求的是一个把根节点和所有叶子断开连接的最小花费. 还是想一个比较\(naive\)的做法 我们令\(dp1[i]\)表示,在\(i\)的子树内, ...

  10. 动态 DP 学习笔记

    不得不承认,去年提高组 D2T3 对动态 DP 起到了良好的普及效果. 动态 DP 主要用于解决一类问题.这类问题一般原本都是较为简单的树上 DP 问题,但是被套上了丧心病狂的修改点权的操作.举个例子 ...

随机推荐

  1. BZOJ2038 [2009国家集训队]小Z的袜子 莫队+分块

    作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从 ...

  2. MySQL--pymysql模块

    import pymysqlaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa连接conn=pymysql.connect(host='127.0.0. ...

  3. 清理messages提示-bash: /var/log/messages: Operation not permitted的处理

    报警提示系统盘容量不足了/var/log下查看messages日志已经很大了,所以就想着把messages清空一下,以此来释放空间.在删除的时候提示没有权限. 看了下日志,发现是大量的haproxy日 ...

  4. OpenStack实践系列⑦深入理解neutron和虚拟机

    OpenStack实践系列⑦深入理解neutron和虚拟机 五.深入理解Neutron 5.1 虚拟机网卡和网桥 [root@node1 ~]# ifconfig brq65c11cc3-8e: fl ...

  5. EasyUI tree 选中父节点子节点全部选中,选中子节点父节点不选中

    需求:EasyUI tree 选中父节点子节点全部选中,选中子节点父节点不选中 效果:   /**   * 给树增加onCheck事件,首先使用cascadeCheck:false属性禁止全选,   ...

  6. python ctypes

    official tutorial for ctypes libhttps://docs.python.org/3/library/ctypes.html 1 ctypes exports the c ...

  7. C/C++ 获取文件大小

    在C语言中测试文件的大小,主要使用二个标准函数. 1.fseek 函数原型:int fseek ( FILE * stream, long int offset, int origin ); 参数说明 ...

  8. 8)django-示例(url传递参数)

    url传递参数有两种,一个是通过普通分组方式,一个是通过带命名分组方式 1.传递方式 1)普通分组方式,传递参数顺序是严格的.如下例子 url(r'^detail-(\d+)-(\d+).html', ...

  9. 【进阶3-3期】深度广度解析 call 和 apply 原理、使用场景及实现(转)

    这是我在公众号(高级前端进阶)看到的文章,现在做笔记  https://github.com/yygmind/blog/issues/22 call() 和 apply() call() 方法调用一个 ...

  10. 关于STM32 __IO 的变量定义

    这个_IO 是指静态 这个 _IO 是指静态 volatile uint32_t 是指32位的无符号整形变量uint32_t 是指32位的无符号整形变量: 搞stm32这么久了,经常看到stm32里面 ...