传送门

树链剖分好题。


考虑分开维护重儿子和轻儿子的信息。

令f[i]f[i]f[i]表示iii为根子树的最优值,h[i]h[i]h[i]表示iii重儿子的最优值,g[i]g[i]g[i]表示iii所有轻儿子的最优值之和。

那么显然有:f[i]=minf[i]=minf[i]=min{h[i]+g[i],val[i]h[i]+g[i],val[i]h[i]+g[i],val[i]}

然后发现这个可以用矩阵来表示。

然后直接用树链合并更新矩阵就行了。

代码:

#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
#define N 200005
#define ll long long
#define inf 2000000000000000000
using namespace std;
inline ll read(){
    ll ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
int cnt,tot,n,q,first[N],pred[N],num[N],fa[N],dep[N],top[N],siz[N],hson[N],bot[N];
struct edge{int v,next;}e[N<<1];
struct Node{
    ll a[2][2];
    Node(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=inf;}
    inline Node operator*(const Node&t){
        Node ret;
        for(int i=0;i<2;++i)for(int j=0;j<2;++j)if(a[i][j]!=inf)for(int k=0;k<2;++k)ret.a[i][k]=min(ret.a[i][k],a[i][j]+t.a[j][k]);
        return ret;
    }
}a[N],T[N<<2];
ll val[N],g[N],f[N];
inline void add(int u,int v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;}
void dfs1(int p){
    siz[p]=1;
    for(int i=first[p];i;i=e[i].next){
        int v=e[i].v;
        if(v==fa[p])continue;
        fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
        if(siz[v]>siz[hson[p]])hson[p]=v;
    }
}
void dfs2(int p,int tp){
    top[p]=tp,pred[num[p]=++tot]=p,bot[tp]=p;
    if(!hson[p]){f[p]=val[p],g[p]=inf;return;}
    dfs2(hson[p],tp),f[p]=f[hson[p]],g[p]=0;
    for(int i=first[p];i;i=e[i].next){
        int v=e[i].v;
        if(v!=fa[p]&&v!=hson[p])dfs2(v,v),g[p]+=f[v];
    }
    f[p]=min(f[p]+g[p],val[p]);
}
inline void build(int p,int l,int r){
    if(l==r){T[p]=a[pred[l]];return;}
    build(lc,l,mid),build(rc,mid+1,r),T[p]=T[rc]*T[lc];
}
inline void update(int p,int l,int r,int k){
    if(l==r){T[p]=a[pred[l]];return;}
    if(k<=mid)update(lc,l,mid,k);
    else update(rc,mid+1,r,k);
    T[p]=T[rc]*T[lc];
}
inline Node query(int p,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return T[p];
    if(qr<=mid)return query(lc,l,mid,ql,qr);
    if(ql>mid)return query(rc,mid+1,r,ql,qr);
    return query(rc,mid+1,r,mid+1,qr)*query(lc,l,mid,ql,mid);
}
inline ll query(int p){return query(1,1,n,num[p],num[bot[top[p]]]).a[0][1];}
inline void change(int p){
    while(p){
        a[p].a[0][1]=val[p],a[p].a[1][1]=g[p],update(1,1,n,num[p]);
        if(p==1)return;
        g[fa[top[p]]]-=f[top[p]],f[top[p]]=query(top[p]);
        g[fa[top[p]]]+=f[top[p]],p=fa[top[p]];
    }
}
int main(){
    n=read();
    for(int i=1;i<=n;++i)val[i]=read();
    for(int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
    dfs1(1),dfs2(1,1);
    for(int i=1;i<=n;++i)a[i].a[0][0]=0,a[i].a[0][1]=val[i],a[i].a[1][1]=g[i];
    build(1,1,n),q=read();
    while(q--){
        int x,y;
        char op[5];
        scanf("%s",op);
        if(op[0]=='Q')x=read(),printf("%d\n",query(x));
        else x=read(),y=read(),val[x]+=y,change(x);
    }
    return 0;
}

2018.10.12 bzoj4712: 洪水(树链剖分)的更多相关文章

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

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

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

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

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

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

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

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

  5. 【BZOJ4712】洪水 树链剖分优化DP+线段树

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

  6. 【UOJ#435】【集训队作业2018】Simple Tree 分块+树链剖分

    题目大意: 有一棵有根树,根为 1 ,点有点权.现在有 m 次操作,操作有 3 种:1 x y w ,将 x 到 y 的路径上的点点权加上 w (其中 w=±1w=±1 ):2 x y ,询问在 x ...

  7. EOJ - 3631 Delivery Service 2018.8华师大月赛(树链剖分+贪心)

    链接:https://acm.ecnu.edu.cn/contest/103/problem/D/ 题意:给你一棵无向边连接的树,边的权值可以任意互换.有m次运输,每次的花费是点u到v路径上边的权值和 ...

  8. 【BZOJ-4127】Abs 树链剖分 + 线段树 (有趣的姿势)

    4127: Abs Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 381  Solved: 132[Submit][Status][Discuss] ...

  9. 【bzoj4127】Abs 树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

随机推荐

  1. myBatis连接MySQL报异常:No operations allowed after connection closed.Connection was implicitly closed

    网站运行一个晚上,早上来上班,发现报错: ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTra ...

  2. div 标签

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. margin和padding的四种写法

    我们经常会看到CSS样式属性中外边距margin和内边距padding的各种用法,这里做一个小结,但只简单介绍margin,因为它们的用法大同小异. 方法一. margin:10px; //4个外边距 ...

  4. 解决Linux命令行为什么变成-bash-3.2$

    在Linux服务器上创建了一个新用户probe,是这样创建的: [root@localhost home]# groupadd -g 501 probe [root@localhost home]# ...

  5. Haskell语言学习笔记(36)Data.List.Zipper

    ListZipper 模块 $ cabal install ListZipper Installed ListZipper-1.2.0.2 Prelude> :m +Data.List.Zipp ...

  6. Ansible Playbook Roles and Include Statements

    介绍 虽然可以在一个非常大的文件中编写一个playbook(您可能会以这种方式开始学习playbook),但最终您将需要重新使用文件并开始组织事情. 在基本级别,饱含任务的文件允许您将配置策略分解成较 ...

  7. spring-boot PageHelper

    分页插件PageHelper 参看了pagehelper-spring-boot,使用起来非常放方便,关于更多PageHelper可以点击https://github.com/pagehelper/M ...

  8. SVN的基本操作

    右键SVN Commit 提交成功了,我们把SVN的服务器端刷新一下 所有的操作如果只是删除本地的文件都不会影响服务器端的文件,除非右键SVN Commit删除文件或者是新增文件才会对服务器端的仓库里 ...

  9. malloc、free、new、delete

    一.C语言中不定大小多维数组的处理: 如果要给二维数组(m*n)分配空间,代码可以写成下面: char **a, i; // 先分配m个指针单元,注意是指针单元 // 所以每个单元的大小是sizeof ...

  10. unix架构

    UNIX Kernel(UNIX内核):指挥机器的运行,控制计算机的资源 UNIX Shell(UNIX外壳):是UNIX内核和用户的接口,是UNXI的命令解释器.目前常用的Shell有3种 Bour ...