因为d>=0,所以一个位置的数只会单调不降并且只会有一次穿过0.

用这个性质,我们我可在线段树中记录正数负数的个数和和,以及最大的负数以及答案.

修改操作:如果当前最大负数+d<=0,那么就直接加到懒惰标记中,否则就暴力向下传递.

因为每个节点最多被额外访问该区间负数个数次,所以所有点总共会被额外访问O(nlogn)次,在加上修改操作和询问操作的普通访问O(mlogn)次,所以时间复杂度是有保证的.

谢谢mhy12345的讲解.

 /**************************************************************
Problem: 4127
User: idy002
Language: C++
Result: Accepted
Time:7872 ms
Memory:49256 kb
****************************************************************/ #include <cstdio>
#include <vector>
#include <algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a) ((a)<0?-(a):(a))
#define oo 0x3f3f3f3f3f3f3f3fLL
#define N 200010
//#define fprintf(...)
using namespace std; typedef long long dnt; void getn( int &v ) {
char ch=getchar();
bool neg = false;
while( ch!='-' && (ch<'' || ch>'') ) ch=getchar();
if( ch=='-' ) {
neg = true;
ch = getchar();
}
v = ch-'';
ch = getchar();
while( ''<=ch && ch<='' ) {
v = v*+ch-'';
ch = getchar();
}
if( neg ) v=-v;
} struct Node {
dnt ans, sum[], cnt[], nmx, tag;
Node *ls, *rs;
inline void init( int v ) {
if( v< ) {
sum[] = v;
cnt[] = ;
sum[] = ;
cnt[] = ;
ans = -v;
tag = ;
nmx = v;
} else {
sum[] = ;
cnt[] = ;
sum[] = v;
cnt[] = ;
tag = ;
ans = v;
nmx = -oo;
}
}
inline void update() {
sum[] = ls->sum[] + rs->sum[];
sum[] = ls->sum[] + rs->sum[];
cnt[] = ls->cnt[] + rs->cnt[];
cnt[] = ls->cnt[] + rs->cnt[];
ans = ls->ans + rs->ans;
nmx = max( ls->nmx, rs->nmx );
}
inline void pushdown() {
if( tag ) {
ls->nmx += tag;
rs->nmx += tag;
ls->sum[] += ls->cnt[]*tag;
ls->sum[] += ls->cnt[]*tag;
rs->sum[] += rs->cnt[]*tag;
rs->sum[] += rs->cnt[]*tag;
ls->ans = ls->sum[]-ls->sum[];
rs->ans = rs->sum[]-rs->sum[];
ls->tag += tag;
rs->tag += tag;
tag = ;
}
}
void modify( int lf, int rg, int L, int R, int delta ) {
if( lf==rg ) {
if( cnt[] ) {
if( sum[]+delta<= ) {
sum[]+=delta;
nmx = sum[];
ans = -sum[];
} else {
sum[] = sum[]+delta;
ans = sum[];
cnt[] = ;
sum[] = cnt[] = ;
nmx = -oo;
}
} else {
sum[]+=delta;
ans = sum[];
}
return;
}
if( L<=lf && rg<=R && nmx+delta<= ) {
nmx += delta;
sum[] += cnt[]*delta;
sum[] += cnt[]*delta;
ans = sum[]-sum[];
tag += delta;
return;
}
pushdown();
int mid=(lf+rg)>>;
if( L<=mid ) ls->modify(lf,mid,L,R,delta);
if( R>mid ) rs->modify(mid+,rg,L,R,delta);
update();
}
dnt query( int lf, int rg, int L, int R ) {
if( L<=lf && rg<=R ) return ans;
pushdown();
int mid=(lf+rg)>>;
dnt rt = ;
if( L<=mid ) rt+=ls->query(lf,mid,L,R);
if( R>mid ) rt+=rs->query(mid+,rg,L,R);
update();
return rt;
}
}pool[N*], *tail=pool, *root; int n, m;
int aa[N], bb[N];
int head[N], dest[N<<], next[N<<], etot;
int fat[N], siz[N], son[N], top[N], dep[N], vid[N], qu[N], bg, ed; void adde( int u, int v ) {
etot++;
dest[etot] = v;
next[etot] = head[u];
head[u] = etot;
}
Node *build( int lf, int rg ) {
Node *nd = ++tail;
if( lf==rg) {
nd->init(bb[lf]);
return nd;
}
int mid=(lf+rg)>>;
nd->ls = build( lf, mid );
nd->rs = build( mid+, rg );
nd->update();
return nd;
}
void build_dcp( int s ) {
// fat dep
fat[s] = ;
dep[s] = ;
qu[bg=ed=] = s;
while( bg<=ed ) {
int u=qu[bg++];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fat[u] ) continue;
fat[v] = u;
dep[v] = dep[u]+;
qu[++ed] = v;
}
}
// siz son
for( int i=ed; i>=; i-- ) {
int u=qu[i], p=fat[u];
siz[u]++;
if( p ) {
siz[p] += siz[u];
if( siz[son[p]]<siz[u] ) son[p]=u;
}
}
// vid top
vid[s] = ;
top[s] = s;
for( int i=; i<=ed; i++ ) {
int u=qu[i];
int cur=vid[u]+;
if( son[u] ) {
vid[son[u]] = cur;
top[son[u]] = top[u];
cur += siz[son[u]];
}
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fat[u] || v==son[u] ) continue;
vid[v] = cur;
top[v] = v;
cur += siz[v];
}
}
// segment tree
for( int i=; i<=n; i++ )
bb[vid[i]] = aa[i];
// for( int i=1; i<=n; i++ )
// fprintf( stderr, "%d ", bb[i] );
// fprintf( stderr, "\n" );
root = build( , n );
}
void modify( int u, int v, int delta ) {
while( top[u]!=top[v] ) {
if( dep[top[u]]<dep[top[v]] ) swap(u,v);
root->modify(,n,vid[top[u]],vid[u],delta);
// fprintf( stderr, "modify( %d %d %d )\n", vid[top[u]], vid[u], delta );
u=fat[top[u]];
}
if( dep[u]<dep[v] ) swap(u,v);
root->modify(,n,vid[v],vid[u],delta);
// fprintf( stderr, "modify( %d %d %d )\n", vid[v], vid[u], delta );
}
dnt query( int u, int v ) {
dnt rt = ;
while( top[u]!=top[v] ) {
if( dep[top[u]]<dep[top[v]] ) swap(u,v);
rt += root->query(,n,vid[top[u]],vid[u]);
// fprintf( stderr, "query( %d %d ) rt = %lld\n", vid[top[u]], vid[u], rt );
u=fat[top[u]];
}
if( dep[u]<dep[v] ) swap(u,v);
rt += root->query(,n,vid[v],vid[u]);
// fprintf( stderr, "query( %d %d ) rt = %lld\n", vid[v], vid[u], rt );
return rt;
}
int main() {
getn(n); getn(m);
for( int i=; i<=n; i++ )
getn(aa[i]);
for( int i=,u,v; i<n; i++ ) {
getn(u); getn(v);
adde( u, v );
adde( v, u );
}
build_dcp();
for( int t=,opt,u,v,d; t<=m; t++ ) {
getn(opt);
if( opt== ) {
getn(u);getn(v);getn(d);
modify( u, v, d );
} else {
getn(u); getn(v);
printf( "%lld\n", query(u,v) );
}
}
}

bzoj 4127 线段树维护绝对值之和的更多相关文章

  1. bzoj 1018 线段树维护连通性

    本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护. 对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边 ...

  2. BZOJ 1018 线段树维护图的连通性问题

    思路: 我们可以搞一棵线段树 对于一段区间有6种情况需要讨论 左上右下.左上右上.左下右下.左下右上 这四种比较好维护 用左上右下举个例子吧 就是左儿子的左上右下&左区间到右区间下面有路&am ...

  3. BZOJ 2124 线段树维护hash值

    思路: http://blog.csdn.net/wzq_QwQ/article/details/47152909 (代码也是抄的他的) 自己写得垃圾线段树怎么都过不了 隔了两个月 再写 再挂 又隔了 ...

  4. BZOJ 1018 线段树维护图连通性

    用8个bool维护即可分别为LURU,LURD,LDRU,LDRD,LULD,RURD,Side[1],Side[2]即可. Side表示这一块有没有接到右边.Merge一下就可以了.码农题,WA了一 ...

  5. [BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】

    题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过  1018,即使它在 ProblemSet 的第一页 ...

  6. [BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

    题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经 ...

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

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

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

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

  9. bzoj 4184: shallot (线段树维护线性基)

    题面 \(solution:\) 这一题绝对算的上是一道经典的例题,它向我们诠释了一种新的线段树维护方式(神犇可以跳过了).像这一类需要加入又需要维护删除的问题,我们曾经是遇到过的像莫对,线段树... ...

随机推荐

  1. 音频自动增益 与 静音检测 算法 附完整C代码【转】

    转自:https://www.cnblogs.com/cpuimage/p/8908551.html 前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用 ...

  2. ADB安装

    1,下载解压 http://adbshell.com/downloads 2,配置路径 比如解压后我放在了C:\Program Files\adb 电脑-->属性-->高级系统设置--&g ...

  3. strace使用详解(未研究)

    (一) strace 命令    用途:打印 STREAMS 跟踪消息. 语法:strace [ mid sid level ] ... 描述:没有参数的 strace 命令将所有的驱动程序和模块中的 ...

  4. JQuery怎么实现页面左侧菜单刷新后保留鼠标点击addclass的样式?

    $('ul.main-menu li a').each(function(){ if($($(this))[0].href==String(window.location)) $(this).pare ...

  5. mvn简单命令

    导出maven项目依赖的jar包 mvn dependency:copy-dependencies -DoutputDirectory=lib 编译Java代码 mvn compile eclipse ...

  6. 产看Linux运行时间

    Linux下如何查看系统启动时间和运行时间 1.uptime命令输出:16:11:40 up 59 days, 4:21, 2 users, load average: 0.00, 0.01, 0.0 ...

  7. Unix IPC之Posix信号量实现生产者消费者

    采用多生产者,多消费者模型. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /**  * 生产者  */ P(nempty); P(mutex); // 写入一个 ...

  8. 最简单删除SQL Server中所有数据的方法(不用考虑表之间的约束条件,即主表与子表的关系)

    其实删除数据库中数据的方法并不复杂,为什么我还要多此一举呢,一是我这里介绍的是删除数据库的所有数据,因为数据之间可能形成相互约束关系,删除操作可能陷入死循环,二是这里使用了微软未正式公开的sp_MSF ...

  9. Kubernetes 概述和搭建(多节点)

    一.Kubernetes整体概述和架构 Kubernetes是什么 Kubernetes是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务.通过Kubernetes能够进行应用的自动化部署和扩缩 ...

  10. bzoj 4034(DFS序+线段树)

    这个题多了一个操作难度直线上升,看完题解才会写 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 ...