线段树练习5(codevs 4927)

Posted Cola

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树练习5(codevs 4927)相关的知识,希望对你有一定的参考价值。

题目描述 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)的主要内容,如果未能解决你的问题,请参考以下文章

CodeVS 4927-线段树练习5

codevs 4927 线段树练习5 线段树基本操作模板

codevs 4927 线段树练习5

codevs 4927 线段树练习5

分块试水--CODEVS4927 线段树练习5

线段树练习5(codevs 4927)