题目描述

小A走到一个山脚下,准备给自己造一个小屋。这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到
山顶放了格水。于是小A面前出现了一个瀑布。作为平民的小A只好老实巴交地爬山堵水。那么问题来了:我们把这
个瀑布看成是一个n个节点的树,每个节点有权值(爬上去的代价)。小A要选择一些节点,以其权值和作为代价将
这些点删除(堵上),使得根节点与所有叶子结点不连通。问最小代价。不过到这还没结束。小A的朋友觉得这样
子太便宜小A了,于是他还会不断地修改地形,使得某个节点的权值发生变化。不过到这还没结束。小A觉得朋友做
得太绝了,于是放弃了分离所有叶子节点的方案。取而代之的是,每次他只要在某个子树中(和子树之外的点完全
无关)。于是他找到你。

输入

输入文件第一行包含一个数n,表示树的大小。

接下来一行包含n个数,表示第i个点的权值。
接下来n-1行每行包含两个数fr,to。表示书中有一条边(fr,to)。
接下来一行一个整数,表示操作的个数。
接下来m行每行表示一个操作,若该行第一个数为Q,则表示询问操作,后面跟一个参数x,表示对应子树的根;若
为C,则表示修改操作,后面接两个参数x,to,表示将点x的权值加上to。
n<=200000,保证任意to都为非负数

输出

对于每次询问操作,输出对应的答案,答案之间用换行隔开。

样例输入

4
4 3 2 1
1 2
1 3
4 2
4
Q 1
Q 2
C 4 10
Q 1

样例输出

3
1
4
 
考虑没有修改的情况:
我们可以树形$DP$,$f[i]$表示堵住以$i$为根的子树的最小代价,显然可以得到转移方程$f[i]=min(val[i],\sum f[to])$其中$val[i]$表示删除$i$点的代价,$to$表示$i$的子节点。我们设$g[i]$表示点$i$所有轻儿子的$f$之和,那么$f[i]=min(val[i],g[i]+f[son[i]])$其中$son[i]$为$i$的重儿子。我们将后面的$f[son[i]]$展开,那么$f[i]=min(val[i],g[i]+min(val[son[i]],g[son[i]]+f[son[son[i]]]))$。可以发现$f[i]$的最小值就是从$i$开始的连续一段重链的$g$值$+$这段重链链尾的$val$值。我们用图更形象地说明:
 
其中第一行为重链,下面为他们各自的轻儿子(一个点的所有轻儿子用一个点代表)。
那么最小值就是一段$g$与一个$val$的和的最小值。这个东西实际上就是固定左端点的最小连续子段和(我们称之为最小连续左端和)。
我们树链剖分后用线段树维护每条重链的最小连续左端和即可。
现在考虑有修改操作的情况:
假设修改点为$x$,那么首先会影响$x$所在重链的最小连续左端和即$x$所在重链链头(假设为$u$)的$f$值,也就会进一步影响$u$的父节点的$g$值及$u$的父节点所在重链的最小连续左端和,以此类推会影响到根节点。我们从$x$节点开始往根方向修改沿途重链上的点维护的信息即可。查询时直接查询以查询点为左端点的最小连续左端和。注意只有修改$x$时修改的是$val$值,其他被修改的点都修改的是$g$值。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll v[200010];
ll g[200010];
ll f[200010];
int tot;
int n,m;
int head[200010];
int next[400010];
int to[400010];
int son[200010];
int top[200010];
int fa[200010];
int bot[200010];
int size[200010];
int s[200010];
int pos[200010];
int q[200010];
int num;
int x,y;
ll z;
char ch[3];
struct miku
{
ll sum;
ll mn;
}t[800010];
void add(int x,int y)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void dfs(int x)
{
size[x]=1;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa[x])
{
fa[to[i]]=x;
dfs(to[i]);
size[x]+=size[to[i]];
if(size[to[i]]>size[son[x]])
{
son[x]=to[i];
}
}
}
}
void dfs2(int x,int tp)
{
s[x]=++num;
q[num]=x;
f[x]=v[x];
top[x]=tp;
if(son[x])
{
dfs2(son[x],tp);
bot[x]=bot[son[x]];
}
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa[x]&&to[i]!=son[x])
{
dfs2(to[i],to[i]);
g[x]+=f[to[i]];
}
}
if(!son[x])
{
bot[x]=x;
}
else
{
f[x]=min(f[x],g[x]+f[son[x]]);
}
}
void pushup(int rt)
{
int ls=rt<<1;
int rs=rt<<1|1;
t[rt].sum=t[ls].sum+t[rs].sum;
t[rt].mn=min(t[ls].sum+t[rs].mn,t[ls].mn);
}
void build(int rt,int l,int r)
{
if(l==r)
{
int x=q[l];
pos[x]=rt;
t[rt].sum=g[x];
t[rt].mn=v[x];
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void updata(int x)
{
int rt=pos[x]>>1;
while(rt)
{
pushup(rt);
rt>>=1;
}
}
miku query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return t[rt];
}
miku ls,rs,res;
int mid=(l+r)>>1;
if(L>mid)
{
return query(rt<<1|1,mid+1,r,L,R);
}
else if(R<=mid)
{
return query(rt<<1,l,mid,L,R);
}
else
{
ls=query(rt<<1,l,mid,L,R);
rs=query(rt<<1|1,mid+1,r,L,R);
res.sum=ls.sum+rs.sum;
res.mn=min(ls.sum+rs.mn,ls.mn);
return res;
}
}
void change(int x,ll val)
{
int now=x;
while(x)
{
ll cnt=query(1,1,n,s[top[x]],s[bot[x]]).mn;
if(x==now)
{
t[pos[x]].mn+=val;
updata(x);
}
else
{
t[pos[x]].sum+=val;
updata(x);
}
val=query(1,1,n,s[top[x]],s[bot[x]]).mn-cnt;
x=fa[top[x]];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&v[i]);
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1);
dfs2(1,1);
build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s",ch);
if(ch[0]=='C')
{
scanf("%d%lld",&x,&z);
change(x,z);
}
else
{
scanf("%d",&x);
printf("%lld\n",query(1,1,n,s[x],s[bot[x]]).mn);
}
}
}

BZOJ4712洪水——动态DP+树链剖分+线段树的更多相关文章

  1. 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp

    题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...

  2. 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp

    题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...

  3. 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点

    题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...

  4. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  5. B20J_3231_[SDOI2014]旅行_树链剖分+线段树

    B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...

  6. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  7. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  8. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  9. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  10. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

随机推荐

  1. 性能调优6:Spool 假脱机调优

    SQL Server的Spool(假脱机)操作符,用于把前一个操作符处理的数据(又称作中间结果集)存储到一个隐藏的临时结构中,以便在执行过程中重用这些数据.这个临时结构都创建在tempdb中,通常的结 ...

  2. Sql 调优总结

    1前言 Sql 语句调优对应用性能非常重要,看了几篇文章,总结了一下数据库优化的方法. 2 数据库 Sql 优化 1 对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by ...

  3. python 可调用对象之类实例

    可调用对象,即任何可以通过函数操作符()来调用的对象. python可调用对象大致可以分为4类: 1.函数 python中有三种函数:内建函数(BIFs).用户自定义函数(UDF).lambda表达式 ...

  4. Vue(三)之前端路由

    01-前端路由 1.前端路由的实现原理 vue+vue-router 主要来做单页面应用(Single Page Application) 为什么我们要做单页面应用? (1)传统的开发方式 url改变 ...

  5. hdu 2063 给男女匹配 (匈牙利算法)

    来源:http://acm.hdu.edu.cn/showproblem.php?pid=2063 题意: 有k个组合a,b组合,代表a愿意与b坐过山车,共m个女生 n个男生,问有多少个满意的匹配 题 ...

  6. iOS--LaunchImage启动页设置及问题解决

    在Assets.xcassets中使用LaunchImage来设置启动图:   一.根据不同屏幕尺寸的需求设置不同的图片,可以参照下图: 1.点击Image.xcassets 进入图片管理,然后右击, ...

  7. MySQL的binlog及关闭方法

    如何关闭MySQL日志,删除mysql-bin.0000*日志文件 - VPS侦探https://www.vpser.net/manage/delete-mysql-mysql-bin-0000-lo ...

  8. php常用方法

    在日常开发中,经常我们使用系统方法或者是自己封装的方法进行项目的开发.再此总结一下!!! 一.对于字符串截取 1.使用mbstring扩展  (注意编码的设置) mb_substr($str,2,5, ...

  9. React Native之微信分享(iOS Android)

    React Native之微信分享(iOS Android) 在使用React Native开发项目的时候,基本都会使用到微信好友或者微信朋友圈分享功能吧,那么今天我就带大家实现以下RN微信好友以及朋 ...

  10. laravel log改为时间格式

    1 providers新建文件 LogRotateServiceProvider.php <?php namespace App\Providers; use Monolog\Formatter ...