码迷,mamicode.com
首页 > 其他好文 > 详细

线段树练习5(codevs 4927)

时间:2017-03-01 23:05:44      阅读:269      评论:0      收藏:0      [点我收藏+]

标签:ios   using   scan   str   turn   input   print   log   表示   

题目描述 Description

有n个数和5种操作

add a b c:把区间[a,b]内的所有数都增加c

set a b c:把区间[a,b]内的所有数都设为c

sum a b:查询区间[a,b]的区间和

max a b:查询区间[a,b]的最大值

min a b:查询区间[a,b]的最小值

输入描述 Input Description

第一行两个整数n,m,第二行n个整数表示这n个数的初始值

接下来m行操作,同题目描述

输出描述 Output Description

对于所有的sum、max、min询问,一行输出一个答案

样例输入 Sample Input

10 6

3 9 2 8 1 7 5 0 4 6

add 4 9 4

set 2 6 2

add 3 8 2

sum 2 10

max 1 7

min 3 6

 

样例输出 Sample Output

49

11

4

 

数据范围及提示 Data Size & Hint

10%:1<n,m<=10

30%:1<n,m<=10000

100%:1<n,m<=100000

保证中间结果在long long(C/C++)、int64(pascal)范围内

 

/*
  线段树的裸题,用分块写略麻烦。
  对于每个块维护两个标记,添加标记和修改标记,修改的时候对于完整的块只修改标记,对于不完整的块,暴力修改,查询也是一样。 
*/
#include<cstdio>
#include<iostream>
#include<cmath>
#define N 100010
#define inf 1000000000
#define lon long long
using namespace std;
int val[N],mx[N],mn[N],tag1[N],tag2[N],bl[N],n,m,len;lon sum[N];

void pushdown(int k){
    if(tag2[k]!=-1){
        for(int i=(k-1)*len+1;i<=min(k*len,n);i++)
            val[i]=tag2[k];
        tag1[k]=0;tag2[k]=-1;
    }
    if(tag1[k]){
        for(int i=(k-1)*len+1;i<=min(k*len,n);i++)
            val[i]+=tag1[k];
        tag1[k]=0;
    }
}

void modify(int x,int y,int z){
    //下放x不完整区间
    int k=bl[x];pushdown(k);
    for(int i=x;i<=min(k*len,y);i++) val[i]+=z;
    sum[k]=0;mx[k]=-inf;mn[k]=inf;
    for(int i=(k-1)*len+1;i<=min(k*len,n);i++)
        sum[k]+=(lon)val[i],mx[k]=max(mx[k],val[i]),mn[k]=min(mn[k],val[i]);
    //下放完整区间 
    for(int i=bl[x]+1;i<bl[y];i++){
        if(tag2[i]!=-1) tag2[i]+=z;
        else tag1[i]+=z;
        sum[i]+=(lon)z*(lon)len;mx[i]+=z;mn[i]+=z; 
    }
    //下放y不完整区间 
    if(bl[x]==bl[y]) return;
    k=bl[y];pushdown(k);
    for(int i=(k-1)*len+1;i<=y;i++) val[i]+=z;
    sum[k]=0;mx[k]=-inf;mn[k]=inf;
    for(int i=(k-1)*len+1;i<=min(k*len,n);i++)
        sum[k]+=(lon)val[i],mx[k]=max(mx[k],val[i]),mn[k]=min(mn[k],val[i]);
}

void change(int x,int y,int z){
    //下放x不完整区间 
    int k=bl[x];pushdown(k);
    for(int i=x;i<=min(k*len,y);i++) val[i]=z;
    sum[k]=0;mx[k]=-inf;mn[k]=inf;
    for(int i=(k-1)*len+1;i<=min(k*len,n);i++)
        sum[k]+=(lon)val[i],mx[k]=max(mx[k],val[i]),mn[k]=min(mn[k],val[i]);
    //下方完整区间
    for(int i=bl[x]+1;i<bl[y];i++)
        tag2[i]=mx[i]=mn[i]=z,sum[i]=(lon)z*(lon)len,tag1[i]=0;
    //下放y不完整区间
    if(bl[x]==bl[y]) return;
    k=bl[y];pushdown(k);
    for(int i=(k-1)*len+1;i<=y;i++) val[i]=z;
    sum[k]=0;mx[k]=-inf;mn[k]=inf;
    for(int i=(k-1)*len+1;i<=min(k*len,n);i++)
        sum[k]+=(lon)val[i],mx[k]=max(mx[k],val[i]),mn[k]=min(mn[k],val[i]);
}

lon querysum(int x,int y){
    lon tot=0;int k=bl[x];
    pushdown(k);
    for(int i=x;i<=min(k*len,y);i++) tot+=(lon)val[i];
    for(int i=bl[x]+1;i<bl[y];i++) tot+=sum[i];
    if(bl[x]==bl[y]) return tot;
    k=bl[y];pushdown(k);
    for(int i=(k-1)*len+1;i<=y;i++) tot+=(lon)val[i];
    return tot;
}

int querymax(int x,int y){
    int maxn=-inf,k=bl[x];
    pushdown(k);
    for(int i=x;i<=min(k*len,y);i++) maxn=max(maxn,val[i]);
    for(int i=bl[x]+1;i<bl[y];i++) maxn=max(maxn,mx[i]);
    if(bl[x]==bl[y]) return maxn;
    k=bl[y];pushdown(k);
    for(int i=(k-1)*len+1;i<=y;i++) maxn=max(maxn,val[i]);
    return maxn;
}

int querymin(int x,int y){
    int minn=inf,k=bl[x];
    pushdown(k);
    for(int i=x;i<=min(k*len,y);i++)minn=min(minn,val[i]);
    for(int i=bl[x]+1;i<bl[y];i++) minn=min(minn,mn[i]);
    if(bl[x]==bl[y]) return minn;
    k=bl[y];pushdown(k);
    for(int i=(k-1)*len+1;i<=y;i++) minn=min(minn,val[i]);
    return minn;
}

int main(){
    scanf("%d%d",&n,&m);
    len=sqrt(n);
    for(int i=1;i<=n/len+1;i++){
        mx[i]=-inf;
        mn[i]=inf;
        tag2[i]=-1;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&val[i]);
        bl[i]=(i-1)/len+1;
        mx[bl[i]]=max(mx[bl[i]],val[i]);
        mn[bl[i]]=min(mn[bl[i]],val[i]);
        sum[bl[i]]+=(lon)val[i];
    }
    char op[10];int x,y,z;
    for(int i=1;i<=m;i++){
        scanf("%s%d%d",op,&x,&y);
        if(op[2]==d||op[2]==t) scanf("%d",&z);
        if(op[2]==d) modify(x,y,z);
        if(op[2]==t) change(x,y,z);
        if(op[2]==m) printf("%lld\n",querysum(x,y));
        if(op[2]==x) printf("%d\n",querymax(x,y));
        if(op[2]==n) printf("%d\n",querymin(x,y));
    }
    return 0;
}

 

线段树练习5(codevs 4927)

标签:ios   using   scan   str   turn   input   print   log   表示   

原文地址:http://www.cnblogs.com/harden/p/6486594.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!