http://acm.hdu.edu.cn/showproblem.php?pid=4107
题意:给定一个数组,初始时数组的值全为0 , 每次给数组中的一段区间增加一个值,若此区间中原先的值就已经超过了P,则该数增加2*val,否则增加val。求若干次增值之后数组最终的元素的值。
算法:线段树 + lazy优化
代码:
/*
HDU 4107 Gangster
Tips : segment Tree + lazy
runtime : 810ms
*/
#include<stdio.h>
#include<string.h>
#define LL(x) (x<<1)
#define RR(x) ((x<<1)|1)
#define MID(a,b) ( (a+b)>>1 )
#define MAX 200001
#define MIN(a,b) (a>b?b:a)
struct Node{
int L,R ; //左右端点的界限
int rank , exp ; //叶子节点的属性 rank表示叶子节点的等级,exp表示叶子节点的当前伤害值
int min_dis ; //区间的属性,表示该区间内与p的值相差最小的值
int lazy ; //区间属性,表示该区间内每个元素都增加的伤害值,也是lazy优化
}NN[4*MAX] ;
int n,m,p;
int ans[MAX] ;
//建树
void Build(int t,int l,int r){
int nl = LL(t) , nr = RR(t) ;
NN[t].L = l ; NN[t].R = r ;
NN[t].rank = 1 ; NN[t].exp = 0 ;
NN[t].min_dis = p ;
NN[t].lazy = 0 ;
if(l == r) return ;
int mid = MID(l,r);
Build(nl,l,mid) ;
Build(nr,mid+1,r) ;
}
//自下而上更新区间的dis_min的值
inline void search(int t){
int nl = LL(t) , nr = RR(t) ;
NN[t].min_dis = MIN(NN[nl].min_dis , NN[nr].min_dis) ;
}
//将该区间内的lazy值释放给它的字节点区间
inline void down(int t){
int nl=LL(t) , nr = RR(t) ;
if(NN[nl].L == NN[nl].R){
NN[nl].exp += NN[nl].rank * NN[t].lazy ;
}
NN[nl].lazy += NN[t].lazy ;
NN[nl].min_dis -= NN[t].lazy ;
if(NN[nr].L == NN[nr].R){
NN[nr].exp += NN[nr].rank * NN[t].lazy ;
}
NN[nr].lazy += NN[t].lazy ;
NN[nr].min_dis -= NN[t].lazy ;
NN[t].lazy = 0 ;
}
//线段树的更新,表示在[l,r]区间内增加一个val的值
inline void update(int t,int l,int r,int val){
int mid = MID(NN[t].L,NN[t].R) ;
int nl = LL(t) , nr = RR(t) ;
if( NN[t].L == NN[t].R ){ //到达了叶子节点
NN[t].exp += NN[t].rank * val ; //计算叶子节点的exp值,并判断是否需要升级
if(NN[t].exp >= p){ //叶子节点需要升级
NN[t].rank = 2 ;
NN[t].min_dis = (1<<30) ;
}
else{ //不需要升级
NN[t].min_dis = p-NN[t].exp ;
}
return ;
}
if(NN[t].L==l && NN[t].R==r){ //查询到了整个的区间
if(NN[t].min_dis <= val){ //区间内又需要升级的叶子节点,此时不能直接lazy,需要释放lazy的值
down(t); //释放原先的lazy
update(nl,NN[nl].L,NN[nl].R,val) ;
update(nr,NN[nr].L,NN[nr].R,val) ;
search(t); //更新此区间的dis_min
}
else{ //直接更新lazy即可
NN[t].lazy += val ;
NN[t].min_dis -= val ;
}
return ;
}
if(NN[t].lazy) //没有找到完整的区间,需要继续递归求解,先释放lazy的值
down(t) ;
if(r<=mid) update(nl,l,r,val);
else if(l>=mid+1) update(nr,l,r,val) ;
else{
update(nl,l,mid,val);
update(nr,mid+1,r,val) ;
}
search(t) ;
return ;
}
//将所有的值都询问出来
void query(int t,int l,int r){
int nl = LL(t) , nr = RR(t) ;
if(NN[t].L == NN[t].R) {
ans[l] = NN[t].exp ;
return ;
}
if(NN[t].lazy) down(t) ;
int mid = MID(NN[t].L,NN[t].R) ;
query(nl,l,mid) ;
query(nr,mid+1,r) ;
}
//输入外挂
inline void scan(int &n){
char cc ;
while(cc=getchar() , cc<'0'|| cc>'9') ;
n = cc - '0' ;
while(cc=getchar() , cc>='0' && cc<='9')
n = n * 10 + cc - '0' ;
}
int main(){
int L,R,val ;
while(scanf("%d %d %d",&n,&m,&p)!=EOF){
Build(1,1,n);
for(int i=1;i<=m;i++){
scan(L) ; scan(R); scan(val);
update(1,L,R,val) ;
}
query(1,1,n) ;
for(int i=1;i<=n;i++){
if(i!=1) printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
return 0 ;
}