[BZOJ4712]洪水-[树链剖分+线段树]
Description
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]洪水-[树链剖分+线段树]的更多相关文章
- 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp
题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- 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 ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
随机推荐
- Oracle密码过期the password has expired解决办法
oracle 出现the password has expired这个问题,今天突然发现项目访问不了,一查发现用不了,也登不进去, 这个问题由是Oracle11g密码过期的原因导致的 调试Web项目的 ...
- SOJ 1085 SCU 简单计算几何
BackGroud Year 2003不知你是否注意到,四川大学每年都会在各宿舍楼里放老鼠药,以解决学生宿舍的老鼠问题. 今年,学校的领导为了更好的展开灭鼠的行动,引进了一项新的技术:SCU(Supe ...
- Gluon 参数读取
ndarray: save , load from mxnet import nd from mxnet.gluon import nn x = nd.ones(3) # nd.save('x',x) ...
- 2、Android-UI(RecyclerView)
2.6.滚动控件-RecylerView ListView虽然使用的效果很好但是也是有缺点的 不使用一些技巧来提升它的运行效率,性能就非常差 扩展性也不是很好 只能实现数据的纵向滚动效果 实现横向滚动 ...
- JSP基本指令
jsp命令指令用来设置与整个jsp页面相关的属性,它并不直接产生任何可见的输出,而只是告诉引擎如何处理其余JSP页面.其一般语法形式为: <%@ 指令名称 属性=“值”%> 三种命令指令分 ...
- centos 清除yum缓存
No package nginx available. yum makecache yum install epel-release yum install nginx
- Luogu[P1108] 低价购买
\(Link\) \(\mathcal{\color{red}{Description}}\) 请你求出一个数列的最长下降子序列长度,并为此求出其方案数. \[1 \leq N \leq 5000\] ...
- Mac 下 SVN 的使用
在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境.在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还 ...
- iOS10 语音播报填坑详解(解决串行播报中断问题)
iOS10 语音播报填坑详解(解决串行播报中断问题) 在来聊这类需求的解决方案之前,咱们还是先来聊一聊这类需求的真实使用场景:语音播报.语音播报需求运用最为广泛的应该是收银对账了,就类似于支付宝.微信 ...
- js 时间转换毫秒的四种方法(转)
将时间转换为毫秒数的方法有四个: Date.parse()Date.UTCvalueOf()getTime() 1. Date.parse():该方法接受一个表示日期的字符串参数,然后尝试根据这个日期 ...