bzoj 4127 线段树维护绝对值之和
2015-06-07 14:57
453 查看
因为d>=0,所以一个位置的数只会单调不降并且只会有一次穿过0.
用这个性质,我们我可在线段树中记录正数负数的个数和和,以及最大的负数以及答案.
修改操作:如果当前最大负数+d<=0,那么就直接加到懒惰标记中,否则就暴力向下传递.
因为每个节点最多被额外访问该区间负数个数次,所以所有点总共会被额外访问O(nlogn)次,在加上修改操作和询问操作的普通访问O(mlogn)次,所以时间复杂度是有保证的.
谢谢mhy12345的讲解.
View Code
用这个性质,我们我可在线段树中记录正数负数的个数和和,以及最大的负数以及答案.
修改操作:如果当前最大负数+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
相关文章推荐
- Linux 常用必备命令
- opencv里调用摄像头和捕捉图像帧的方案
- 机器学习 鲁棒的基于高斯概率密度的异常点检测(novelty detection) ellipticalenvelope算法
- 网站优化:测试网站速度的8款免费工具推荐
- kali linux 的初始化及数据库postgresql的初始化并链接
- Linux有问必答:Linux上如何查看种子文件的内容
- 在ecshop模板使用自定义函数
- 不要再坑人啦!NSOperation才是苹果推荐使用的多线程技术!
- [转]CentOS设置程序开机自启动的方法
- CoPilot O
- 如何在CentOS 7.x中安装OpenERP(Odoo)
- centos7安装codeblocks教程
- Nginx配置文件详细说明
- CentOS 6.5 编译安装 gcc-4.9.2
- eclipse + tomcat
- openfire+spark+smack实现即时通讯
- openfire+spark+smack实现即时通讯
- <Linux内核源码>文件系统VFS内核4.0.4版本基本概念源码
- Linux下面的DHCP 服务器配置
- 详解linux vi命令用法