您的位置:首页 > 其它

线段树练习5(codevs 4927)

2017-03-01 22:07 302 查看
题目描述 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
,mx
,mn
,tag1
,tag2
,bl
,n,m,len;lon sum
;

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: