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. BZOJ4446:[SCOI2015]小凸玩密室(树形DP)

    Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室. 每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要 ...

  2. luogu P2015 二叉苹果树

    嘟嘟嘟 这应该算一道树形背包吧,虽然我还是分不太清树形背包和树形dp的区别…… 首先dp[i][u][j] 表示在u的前 i 棵子树中,留了 j 条树枝时最大的苹果数量,而且根据题目描述,这些留下的树 ...

  3. SpringBoot实战(一)之构建RestFul风格

    RestFul风格是一种非常流行的架构风格,相关实战可以参考我的这篇博客:SSM框架之RestFul示例 论文可参考:https://www.ics.uci.edu/~fielding/pubs/di ...

  4. Linux开启路由的方法

    Linux开启路由的命令很简单,只需要一条命令即可: [root@localhost ~]# echo 1 > /proc/sys/net/ipv4/ip_forward 这个只是临时修改,如果 ...

  5. CC2640R2F&TI-RTOS 拿到 TI CC2640R2F 开发板 第二件事就是 LED 驱动 ,点个灯

    /* * board_led.c * * Created on: 2018年7月3日 * Author: admin */ #include "board_uart.h" #inc ...

  6. HDU 3695 Computer Virus on Planet Pandora (AC自己主动机)

    题意:有n种病毒序列(字符串),一个模式串,问这个字符串包括几种病毒. 包括相反的病毒也算.字符串中[qx]表示有q个x字符.具体见案列. 0 < q <= 5,000,000尽然不会超, ...

  7. VB.NET &amp; Visual Basic

    当看到VB.NET者这本书籍的时候,翻开文件夹唯一的感受就是:这不和VB一样吗?究竟有什么差别呢? 1)版本号: 又一次回想VB,能够发现事实上他是Microsoft退出的基于Windows操作系统环 ...

  8. 使用XWAF框架(5)——XML解析器:CXDP

    XWAF推出了自己的组合式XML文档解析器,英文名叫:“CXDP”,是“Combined XML Document Parser”的缩写.核心代码属XWAF原创,注释.日志和帮助文档采用全中文描述,特 ...

  9. II、Python HelloWorld

    大家都不是小孩子了,直接上 IDE 现在有个大问题!!没有解析器啊 这样 解析器地址比他多个 e OJBK

  10. eclipse安装activiti插件

    参考: https://blog.csdn.net/augustaurora/article/details/59618737 https://blog.csdn.net/qq_33547950/ar ...