因为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. linux下使用indent整理代码(代码格式化)【转】

    转自:https://blog.csdn.net/jiangjingui2011/article/details/7197069 常用的设置: indent -npro -kr -i8 -ts8 -s ...

  2. Android性能测试工具之APT

    1.APT工具简介: APT是一个eclipse插件,可以实时监控Android手机上多个应用的CPU.内存数据曲线,并保存数据:另外还支持自动获取内存快照.PMAP文件分析等,方便开发人员自测或者测 ...

  3. netstat-ll-grep-nohup-df-supervisord

    ============http://man.linuxde.net/=========== 0 vi / n是查找下一个,alt+n是上一个  u撤销上一步,回到上一步 1. 根据进程号(4974) ...

  4. 【前端vue开发】vue项目使用sass less扩展语言所要安装的依赖

    1.创建一个基于 webpack 模板的新项目 $ vue init webpack myvue 2.在当前目录下,安装依赖 $ cd myvue $ npm install 3.安装sass的依赖包 ...

  5. 利用sql server直接创建日历

    看到网上有高手直接用sql查询创建日历,也想自己动手实践一遍.笔者这里的实现和网上的都没有什么区别,思路也没有什么新意.觉得好玩,就把它记下来吧. 一.准备知识1.sql的with关键字关于with和 ...

  6. SQL SERVER 收缩数据库的命令

    --备份数据库 BACKUP DATABASE testdb TO DISK='d:\data\testdb20070906.bak' --清空日志 DUMP TRANSACTION testdb W ...

  7. SonarQube代码质量管理工具的安装(Linux)

    一.安装配置sonar 1.Sonar介绍 Sonar是一个用于代码质量管理的开源平台,用于管理Java源代码的质量.通过插件机制,Sonar 可以集成不同的测试工具,代码分析工具,以及持续集成工具, ...

  8. CF 586B 起点到终点的最短路和次短路之和

    起点是右下角  终点是左上角 每次数据都是两行的点  输入n 表示有n列 接下来来的2行是 列与列之间的距离 最后一行是  行之间的距离 枚举就行   Sample test(s) input 41 ...

  9. Web前端开发最佳实践(7):使用合理的技术方案来构建小图标

    大家都对网站上使用的小图标肯定都不陌生,这些小图标作为网站内容的点缀,增加了网站的美观度,提高了用户体验,可是你有没有看过在这些网站中使用的图标都是用什么技术实现的?虽然大部分网站还是使用普通的图片实 ...

  10. Codeforces Round #323 (Div. 2) E - Superior Periodic Subarrays

    E - Superior Periodic Subarrays 好难的一题啊... 这个博客讲的很好,搬运一下. https://blog.csdn.net/thy_asdf/article/deta ...