bzoj 4127 线段树维护绝对值之和
因为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 线段树维护绝对值之和的更多相关文章
- bzoj 1018 线段树维护连通性
本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护. 对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边 ...
- BZOJ 1018 线段树维护图的连通性问题
思路: 我们可以搞一棵线段树 对于一段区间有6种情况需要讨论 左上右下.左上右上.左下右下.左下右上 这四种比较好维护 用左上右下举个例子吧 就是左儿子的左上右下&左区间到右区间下面有路&am ...
- BZOJ 2124 线段树维护hash值
思路: http://blog.csdn.net/wzq_QwQ/article/details/47152909 (代码也是抄的他的) 自己写得垃圾线段树怎么都过不了 隔了两个月 再写 再挂 又隔了 ...
- BZOJ 1018 线段树维护图连通性
用8个bool维护即可分别为LURU,LURD,LDRU,LDRD,LULD,RURD,Side[1],Side[2]即可. Side表示这一块有没有接到右边.Merge一下就可以了.码农题,WA了一 ...
- [BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】
题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过 1018,即使它在 ProblemSet 的第一页 ...
- [BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】
题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- bzoj 4184: shallot (线段树维护线性基)
题面 \(solution:\) 这一题绝对算的上是一道经典的例题,它向我们诠释了一种新的线段树维护方式(神犇可以跳过了).像这一类需要加入又需要维护删除的问题,我们曾经是遇到过的像莫对,线段树... ...
随机推荐
- 用jquery实现toast的原理
function toast(mess){ var str='<div class="mess"><span></span></div&g ...
- Material Design In Action——重构bilibili客户端
前言 哔哩哔哩动画是中国大陆的一家弹幕视频网站,在中国二次元用户中颇受欢迎. 哔哩哔哩动画之前推出过采用 Android Design 的 Android 客户端,虽然有使用了部分过时控件(例如 Sc ...
- 畸形的 dockerfile中的COPY命令-
dockerfile中的COPY是指COPY 指定目录的“子级目录”下所有的目录和文件,到指定目录中,这个shell中的cp命令大相径庭,使得很多人纳闷,怎么cpy过去的文件不是自己想要的
- linux文件管理 -> vim编辑总结
vi和vim命令是linux中强大的文本编辑器, 由于Linux系统一切皆文件,而配置一个服务就是在修改其配置文件的参数.vim编辑器是运维工程师必须掌握的一个工具, 没有它很多工作都无法完成.vim ...
- WebApi参数问题方案
原文:http://www.cnblogs.com/landeanfen/p/5337072.html
- xgboost gbdt特征点分烈点
lightGBM与XGBoost的区别:(来源于:http://baijiahao.baidu.com/s?id=1588002707760744935&wfr=spider&for= ...
- 蛮力法解决0_1背包问题新思路-——利用C语言位域类型
废话不说了,直接上代码 #include<stdio.h> #include<math.h> #define N 5 //物品种类数目 #define CAPACITY 6 / ...
- python之assert断言
assert只是一个检查,为真不做任何事,不为真时,抛出异常,并包含错误信息 1.根据布尔值判断 2.判断是否相等 3.返回值是否为空 4.是否包含某值 x in y 其他方法,可以参考http:// ...
- [USACO16OPEN]248
传送门啦 分析: 一个裸的区间dp,我们只需要注意合并的时候并不像2048那样加倍,每次都加1就好了 #include <iostream> #include <cstring> ...
- HDU 3613 Best Reward(manacher求前、后缀回文串)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613 题目大意: 题目大意就是将字符串s分成两部分子串,若子串是回文串则需计算价值,否则价值为0,求分 ...