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 ; }