题目描述

给出一棵树,点有点权。多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值。

输入

输入文件第一行包含一个数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

关于动态dp可以参考陈俊锟的PPT。

如果dp是静态的,设 $f[i]$ 表示以 $i$ 为根的子树满足条件的最小代价,那么有:$f[i]=\text{min}(v[i],\sum\limits_{i\to j}f[j])$ 。

当这个dp在序列上进行时,我们比较容易使用线段树维护序列动态dp。

当这个dp在树上进行时,考虑将这棵树轻重链剖分,转化为序列问题。

设 $y$ 为 $x$ 的重儿子,所有 $x$ 的轻儿子的 $f$ 值之和为 $g[x]$ ,那么有:$f[x]=\text{min}(v[x],f[y]+g[x])$ 。

这个形式类似于最小连续子段和中的最小前缀和。使用线段树维护最小前缀和(在重链这一段区间的某位置选出一个点使得总代价 $前面的g+当前的v$ 最小)及总和(这段区间都不选,所有的 $g$ 之和)。线段树的叶子节点有:最小前缀和为 $v$ ,总和为 $g$ 。

当修改时,首先影响到的时修改节点所在的重链,我们把对应节点的 $v$ 修改;然后会影响链顶的 $f$ 值,影响轻链的转移,再不断把链顶的父亲节点的 $g$ 修改。

当查询时,直接查询所求点所在重链上,该点到链底在线段树上的最小前缀和即为答案。

时间复杂度:修改时为 $O(\log^2n)$ ,查询时为 $O(\log n)$ 。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
using namespace std;
typedef long long ll;
struct data
{
ll sum , ls;
data() {}
data(ll g , ll v) {sum = g , ls = v;}
inline data operator+(const data &a)const
{
return data(sum + a.sum , min(sum + a.ls , ls));
}
}a[N << 2] , w[N];
int head[N] , to[N << 1] , next[N << 1] , cnt , fa[N] , si[N] , bl[N] , end[N] , pos[N] , tot , n;
ll v[N] , f[N] , g[N];
char str[5];
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs1(int x)
{
int i;
si[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x])
fa[to[i]] = x , dfs1(to[i]) , si[x] += si[to[i]];
}
void dfs2(int x , int c)
{
int i , k = 0;
bl[x] = c , pos[x] = ++tot , end[x] = x , f[x] = v[x];
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x] && si[to[i]] > si[k])
k = to[i];
if(k)
{
dfs2(k , c) , end[x] = end[k];
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x] && to[i] != k)
dfs2(to[i] , to[i]) , g[x] += f[to[i]];
f[x] = min(f[x] , f[k] + g[x]);
}
w[pos[x]] = data(g[x] , v[x]);
}
inline void pushup(int x)
{
a[x] = a[x << 1] + a[x << 1 | 1];
}
void build(int l , int r , int x)
{
if(l == r)
{
a[x] = w[l];
return;
}
int mid = (l + r) >> 1;
build(lson) , build(rson);
pushup(x);
}
void updatev(int p , ll v , int l , int r , int x)
{
if(l == r)
{
a[x].ls += v;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) updatev(p , v , lson);
else updatev(p , v , rson);
pushup(x);
}
void updateg(int p , ll g , int l , int r , int x)
{
if(l == r)
{
a[x].sum += g;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) updateg(p , g , lson);
else updateg(p , g , rson);
pushup(x);
}
data query(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return a[x];
int mid = (l + r) >> 1;
if(e <= mid) return query(b , e , lson);
else if(b > mid) return query(b , e , rson);
else return query(b , e , lson) + query(b , e , rson);
}
inline void modify(int x , ll v)
{
int y = x;
ll t;
while(x)
{
t = query(pos[bl[x]] , pos[end[x]] , 1 , n , 1).ls;
if(x == y) updatev(pos[x] , v , 1 , n , 1);
else updateg(pos[x] , v , 1 , n , 1);
v = query(pos[bl[x]] , pos[end[x]] , 1 , n , 1).ls - t , x = fa[bl[x]];
}
}
int main()
{
int m , i , x , y;
ll z;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &v[i]);
for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
dfs1(1) , dfs2(1 , 1);
build(1 , n , 1);
scanf("%d" , &m);
while(m -- )
{
scanf("%s%d" , str , &x);
if(str[0] == 'C') scanf("%lld" , &z) , modify(x , z);
else printf("%lld\n" , query(pos[x] , pos[end[x]] , 1 , n , 1).ls);
}
return 0;
}

【bzoj4712】洪水 树链剖分+线段树维护树形动态dp的更多相关文章

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

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

  2. POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )

    POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...

  3. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

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

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

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

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

  6. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  7. B20J_2243_[SDOI2011]染色_树链剖分+线段树

    B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...

  8. 2019西北工业大学程序设计创新实践基地春季选拔赛 I Chino with Rewrite (并查集+树链剖分+线段树)

    链接:https://ac.nowcoder.com/acm/contest/553/I 思路:离线整棵树,用并查集维护下联通的情况,因为值只有60个,用2的x(1<=x<=60)次方表示 ...

  9. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

随机推荐

  1. 【oracle】oracle常用命令汇总

    查看数据库状态(普通用户登录要保证数据库是open状态) SQL> select status from v$instance; 创建用户(新用户需要授予连接权限才能连上数据库) SQL> ...

  2. Maven 依赖节点总结

    首先是log4j: <!--哎,神特么的log4j,版本不对就Spring AOP前置增强 new不出来--><dependency> <groupId>log4j ...

  3. 经典简约风格教师求职简历免费word模板

    20款经典简约风格教师求职简历免费word模板,也可用于其他专业和职业,个人免费简历模板,个人简历表免费,个人简历表格. 声明:该简历模板仅用于个人欣赏使用,请勿用于商业用途,谢谢. 下载地址:百度网 ...

  4. 报错:Cannot create PoolableConnectionFactory (The server time zone value 'CST' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverT

    报错:Cannot create PoolableConnectionFactory (The server time zone value 'CST' is unrecognized or repr ...

  5. monkey测试入门3

    本文要感谢一起战斗过的点时小伙伴,程童鞋 打开开始 输入cmd 看到它的目录地址 然后把adb压缩包解压到该地址 插入数据线 打开手机设置打开开发者选项 打开USB调试 右键点击我的电脑 选择管理 左 ...

  6. vue 组件-父组件传值给子组件

    父组件通过属性,传值给子组件,子组件通过,props数组里的名称来接受父组件传过来的值. HTML部分: <div id="app"> <tmp1 :parent ...

  7. GitHub笔记(二)——远程仓库的操作

    二 远程仓库 1 创建联系 第1步:创建SSH Key.在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一 ...

  8. 开发简单的IO多路复用web框架

    自制web框架 1.核心IO多路复用部分 # -*- coding:utf-8 -*- import socket import select class Snow(): def __init__(s ...

  9. 解决maven update project 后项目jdk变成1.5

    http://blog.csdn.net/jay_1989/article/details/52687934

  10. WebGL学习笔记七点一

    第六章讲的是一些GL的一些语法,前面已经涉及,学习时直接跳过,来看第七章,第七章是真正意义的三维立体的出现,其实图形绘制方法是差不多的,就是Z坐标此时不再为0,所以很容易能构造出一些立体图形,但是立体 ...