您的位置:首页 > 运维架构

bzoj 4127 线段树维护绝对值之和

2015-06-07 14:57 453 查看
因为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<'0' || ch>'9') ) ch=getchar();
if( ch=='-' ) {
neg = true;
ch = getchar();
}
v = ch-'0';
ch = getchar();
while( '0'<=ch && ch<='9' ) {
v = v*10+ch-'0';
ch = getchar();
}
if( neg ) v=-v;
}

struct Node {
dnt ans, sum[2], cnt[2], nmx, tag;
Node *ls, *rs;
inline void init( int v ) {
if( v<0 ) {
sum[0] = v;
cnt[0] = 1;
sum[1] = 0;
cnt[1] = 0;
ans = -v;
tag = 0;
nmx = v;
} else {
sum[0] = 0;
cnt[0] = 0;
sum[1] = v;
cnt[1] = 1;
tag = 0;
ans = v;
nmx = -oo;
}
}
inline void update() {
sum[0] = ls->sum[0] + rs->sum[0];
sum[1] = ls->sum[1] + rs->sum[1];
cnt[0] = ls->cnt[0] + rs->cnt[0];
cnt[1] = ls->cnt[1] + rs->cnt[1];
ans = ls->ans + rs->ans;
nmx = max( ls->nmx, rs->nmx );
}
inline void pushdown() {
if( tag ) {
ls->nmx += tag;
rs->nmx += tag;
ls->sum[0] += ls->cnt[0]*tag;
ls->sum[1] += ls->cnt[1]*tag;
rs->sum[0] += rs->cnt[0]*tag;
rs->sum[1] += rs->cnt[1]*tag;
ls->ans = ls->sum[1]-ls->sum[0];
rs->ans = rs->sum[1]-rs->sum[0];
ls->tag += tag;
rs->tag += tag;
tag = 0;
}
}
void modify( int lf, int rg, int L, int R, int delta ) {
if( lf==rg ) {
if( cnt[0] ) {
if( sum[0]+delta<=0 ) {
sum[0]+=delta;
nmx = sum[0];
ans = -sum[0];
} else {
sum[1] = sum[0]+delta;
ans = sum[1];
cnt[1] = 1;
sum[0] = cnt[0] = 0;
nmx = -oo;
}
} else {
sum[1]+=delta;
ans = sum[1];
}
return;
}
if( L<=lf && rg<=R && nmx+delta<=0 ) {
nmx += delta;
sum[0] += cnt[0]*delta;
sum[1] += cnt[1]*delta;
ans = sum[1]-sum[0];
tag += delta;
return;
}
pushdown();
int mid=(lf+rg)>>1;
if( L<=mid ) ls->modify(lf,mid,L,R,delta);
if( R>mid ) rs->modify(mid+1,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)>>1;
dnt rt = 0;
if( L<=mid ) rt+=ls->query(lf,mid,L,R);
if( R>mid ) rt+=rs->query(mid+1,rg,L,R);
update();
return rt;
}
}pool[N*3], *tail=pool, *root;

int n, m;
int aa
, bb
;
int head
, dest[N<<1], next[N<<1], etot;
int fat
, siz
, son
, top
, dep
, vid
, qu
, 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)>>1;
nd->ls = build( lf, mid );
nd->rs = build( mid+1, rg );
nd->update();
return nd;
}
void build_dcp( int s ) {
//  fat dep
fat[s] = 0;
dep[s] = 1;
qu[bg=ed=1] = 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]+1;
qu[++ed] = v;
}
}
//  siz son
for( int i=ed; i>=1; 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] = 1;
top[s] = s;
for( int i=1; i<=ed; i++ ) {
int u=qu[i];
int cur=vid[u]+1;
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=1; 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( 1, 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(1,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(1,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 = 0;
while( top[u]!=top[v] ) {
if( dep[top[u]]<dep[top[v]] ) swap(u,v);
rt += root->query(1,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(1,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=1; i<=n; i++ )
getn(aa[i]);
for( int i=1,u,v; i<n; i++ ) {
getn(u); getn(v);
adde( u, v );
adde( v, u );
}
build_dcp(1);
for( int t=1,opt,u,v,d; t<=m; t++ ) {
getn(opt);
if( opt==1 ) {
getn(u);getn(v);getn(d);
modify( u, v, d );
} else {
getn(u); getn(v);
printf( "%lld\n", query(u,v) );
}
}
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: