Description

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

Solution

这道题真的是666。。

我们设g[x]为堵住该点所有子树的和,v[x]为堵住该点的代价,则f[x]=min(g[x],v[x])。现在我们要给v[x]加上to。

1,v[x]>=g[x],v[x]加多少都不会有影响,过;

2,v[x]<=g[x]&&v[x]+to<=g[x],则g[fa[x]]+=to,如果f[fa[x]]改变,则还需要接着往上推。

3,v[x]<=g[x]&&v[x]+to>g[x],则g[fa[x]]+=-v[x]+g[x],如果f[fa[x]]改变,同样需要接着往上推。

对于情况1,直接处理掉就ok了。

我们考虑优化情况2和3的处理。在这里我们采用树剖+线段树。线段树存储v[x]-g[x]。

对于点x,我们沿着重链往上,如果在某条重链上都是情况2或3,直接加就好;反之在这条重链上二分。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
int n,x,y;
ll v[],_g[],dp[],d;
struct node{int y,nxt;
}g[];int h[],tot=;
int m;char ch[]; int fa[],dep[],son[],top[],sz[];
int cnt=,dfn[],id[]; struct XD_TREE
{
ll mn[],tag[];
void build(int k,int l,int r)
{
if (l==r) {mn[k]=v[dfn[l]]-_g[dfn[l]];return;}
int mid=(l+r)/;
build(k<<,l,mid);build(k<<|,mid+,r);
mn[k]=min(mn[k<<],mn[k<<|]);
}
void downtag(int k)
{
mn[k<<]-=tag[k];mn[k<<|]-=tag[k];
tag[k<<]+=tag[k];tag[k<<|]+=tag[k];
tag[k]=;
}
int modify(int k,int l,int r,int askl,int askr,ll d)
{
if (l==r){
mn[k]-=d;tag[k]+=d;
if (mn[k]<=) return dfn[l];
return ;
}
if (askl<=l&&r<=askr){
if (mn[k]>d)
{
mn[k]-=d;tag[k]+=d;return ;
}
}
if (tag[k]!=) downtag(k);
int mid=(l+r)/,re=;
if (askr>mid) re=modify(k<<|,mid+,r,askl,askr,d);
if (askl<=mid&&!re) re=modify(k<<,l,mid,askl,askr,d);
mn[k]=min(mn[k<<],mn[k<<|]);
return re;
}
ll query(int k,int l,int r,int ask)
{
if (l==r) return mn[k];
if (tag[k]!=) downtag(k);
int mid=(l+r)/;
if (ask<=mid) return query(k<<,l,mid,ask);
else return query(k<<|,mid+,r,ask);
}
}X;
struct TREE_LINK//树剖
{
void dfs1(int x,int f)
{
fa[x]=f;dep[x]=dep[f]+;sz[x]=;
for(int i=h[x];i;i=g[i].nxt)
if (g[i].y!=f) {
dfs1(g[i].y,x);
sz[x]+=sz[g[i].y];
son[x]=(sz[son[x]]>=sz[g[i].y])?son[x]:g[i].y;
_g[x]+=dp[g[i].y];
}
if (sz[x]>) dp[x]=min(_g[x],v[x]);else dp[x]=v[x],_g[x]=1e9;
}
void dfs2(int x)
{
dfn[++cnt]=x;id[x]=cnt;
top[x]=son[fa[x]]==x?top[fa[x]]:x;
if (son[x]) dfs2(son[x]);
for (int i=h[x];i;i=g[i].nxt)
if (g[i].y!=fa[x]&&g[i].y!=son[x]) dfs2(g[i].y);
}
void work(int x,ll d)
{
if (!x||d<=) return;
while (x)
{
int t=X.modify(,,n,id[top[x]],id[x],d);
if (t) {work(fa[t],X.query(,,n,id[t])+d);break;}
x=fa[top[x]];
}
}
}T;
ll getg(int x){return v[x]-X.query(,,n,id[x]);}
int main()
{
scanf("%d",&n);
for (int i=;i<=n;i++) scanf("%lld",&v[i]);
for (int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
g[++tot]=node{y,h[x]};h[x]=tot;
g[++tot]=node{x,h[y]};h[y]=tot;
}
T.dfs1(,);
T.dfs2();
X.build(,,n);
scanf("%d",&m);
for (int i=;i<=m;i++)
{
scanf("%s",ch);
if (ch[]=='Q')
{
scanf("%d",&x);
ll gg=getg(x);
printf("%lld\n",min(gg,v[x]));
} else
{
scanf("%d%lld",&x,&d);
v[x]+=d;
X.modify(,,n,id[x],id[x],-d);
ll gg=getg(x);
if (v[x]-d>=gg) continue;
if (v[x]<=gg) T.work(fa[x],d);
else T.work(fa[x],gg-v[x]+d);
}
}
}
 

[BZOJ4712]洪水-[树链剖分+线段树]的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

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

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

  8. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  9. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  10. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

随机推荐

  1. Windows7下安装配置PostgreSQL10

    PostgreSQL安装: 一.windows7下安装过程首先上PostgreSQL官方网站的下载页面https://www.postgresql.org/download/windows/,下载本软 ...

  2. 2018-2019-2 网络对抗技术 20165322 Exp6 信息搜集与漏洞扫描

    2018-2019-2 网络对抗技术 20165322 Exp6 信息搜集与漏洞扫描 目录 实验原理 实验内容与步骤 各种搜索技巧的应用 DNS IP注册信息的查询 基本的扫描技术 漏洞扫描 基础问题 ...

  3. BZOJ3926:[ZJOI2015]诸神眷顾的幻想乡(广义SAM)

    Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...

  4. jquery mobile header title左对齐 button右对齐

    <div data-theme="b" data-role="header" data-position="fixed"> &l ...

  5. springboot项目用maven打jar包

    clean package -Dmaven.test.skip=true idea eclipse STS

  6. linux(Centos7系统)中安装JDK、Tomcat、Mysql

    安装前准备两个工具:(360可以安装) 1.JDK的安装 使用yum命令安装 .查看是否已安装JDK # yum list installed |grep java .卸载CentOS系统Java环境 ...

  7. 《Android应用测试与调试实战》读书笔记

    一 本书概述 自动化测试篇:Android应用可以使用Java语言配合SDK,也可以使用HTML5技术,还可以用C/C++语言配合NDK技术编写,本书中涵盖了针对这三种技术编写的应用所采用的测试技术. ...

  8. linux内核追踪(trace)(QEMU+gdb)

    1.引言 Linux内核是一个很大的模块,如果只是看源码有时会难以理解Linux内核的一些代码设计情况,如果可以结合Linux内核运行同时阅读源码再好不过,本文大致介绍Linux内核追踪方式,采用工具 ...

  9. SharePoint2010代码启动工作流

    1. private void StartWorkFlow() { //获得该列表上的发布的所有工作流 SPWorkflowAssociationCollection wfAssociationCol ...

  10. 公司内网静态IP,外网无线动态IP 同时上网,不必再切换网卡啦 route 命令给你搞定。

    一: 公司内网:192.168.55.101   255.255.255.0    192.168.55.1  网关 外网:192.168.20.101  255.255.255.0   192.16 ...