因为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. flask基础之请求处理核心机制(五)

    前言 总结一下flask框架的请求处理流程. 系列文章 flask基础之安装和使用入门(一) flask基础之jijia2模板使用基础(二) flask基础之jijia2模板语言进阶(三) flask ...

  2. python内置模块之itertools

    前言 itertools模块是python内置的迭代器模块,定义了可生成多种迭代器的函数,用来代替可迭代对象的遍历等操作,节约内存. 迭代器函数的类型 无限迭代器:包括count.cycle.repe ...

  3. java浅复制与深手动构造实现

    首先来看看浅拷贝和深拷贝的定义: 浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝. 深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的 ...

  4. 08 Packages 包

    Packages   Standard library Other packages Sub-repositories Community Standard library Name Synopsis ...

  5. openlayers常用操作

    1.坐标转换 根据当前坐标系与目标坐标系进行转换ol.proj.transform(coordinate, source, destination);  //coordinate:数组:source: ...

  6. 移动端默认meta标签

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><met ...

  7. 简单计算器的C实现-函数指针,main函数传参

    /** 程序功能:简单计算器,实现加减乘除平方* 作者版本日期:2015.11.08 zhouhb OK* 源代码:李明 <新概念C语言培训>第33集 C语言Shell命令解释器的实现* ...

  8. dede图集内容页调用

    {dede:productimagelist} <li> <img src="[field:imgsrc/]" width="92" heig ...

  9. 20165203《Java程序设计》第二周Java学习总结

    教材学习内容总结 第二章 (一)标识符 注意: 标识符由字母.下画线.美元符号和数字组成,长度不受限制. 标识符第一个字符不能是数学字符. 标识符不能是关键字. 标识符不能是true.false和nu ...

  10. TeamViewer的下载地址,低调低调

    https://github.com/cary-zhou/TeamViewer13-Crack