线段树练习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)的主要内容,如果未能解决你的问题,请参考以下文章