线段树练习 5 codevs 4927
•闲话:今天调了一天的线段树,结果一下午一道题都没做QAQ,现在一看到代码就眼疼。。。感觉要很久才能恢复过来orz… 不过这个题对于线段树来说应该是个很好的模板题2333
题面
有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<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
const int MAXN=1e6+2;
struct Maple{
ll l,r,minn,maxn,sum,add,flag;
}Tree[MAXN<<2];
ll N,M,x,y,z;
ll a[MAXN<<2];
void Dodata(ll n)
{
Tree[n].minn=min(Tree[n<<1].minn,Tree[n<<1|1].minn);
Tree[n].maxn=max(Tree[n<<1].maxn,Tree[n<<1|1].maxn);
Tree[n].sum=Tree[n<<1].sum+Tree[n<<1|1].sum;
}
void build(ll l,ll r,ll n)
{
Tree[n].l=l,Tree[n].r=r;
int mid=(l+r)>>1;
if(l==r)
{
Tree[n].sum=Tree[n].minn=Tree[n].maxn=a[l];
return ;
}
build(l,mid,n<<1);
build(mid+1,r,n<<1|1);
Dodata(n);
}
ll DoSum(ll n,ll x)
{
return (Tree[n].r-Tree[n].l+1)*x;
}
void Spread(ll n)
{
ll &a=Tree[n].add;
if(Tree[n].flag)
{
Tree[n<<1].add=Tree[n<<1].minn=Tree[n<<1].maxn=a;
Tree[n<<1|1].add=Tree[n<<1|1].minn=Tree[n<<1|1].maxn=a;
Tree[n<<1].flag=Tree[n<<1|1].flag=1;
Tree[n<<1].sum=DoSum(n<<1,a);
Tree[n<<1|1].sum=DoSum(n<<1|1,a);
Tree[n].add=Tree[n].flag=0;
return ;
}
Tree[n<<1].add+=a;
Tree[n<<1|1].add+=a;
Tree[n<<1].sum+=DoSum(n<<1,a);
Tree[n<<1|1].sum+=DoSum(n<<1|1,a);
Tree[n<<1].minn+=a;
Tree[n<<1|1].minn+=a;
Tree[n<<1].maxn+=a;
Tree[n<<1|1].maxn+=a;
a=0;
}
ll Ask_Sum(ll n,ll l,ll r)
{
ll L=Tree[n].l,R=Tree[n].r;
if(l<=L&&r>=R)
return Tree[n].sum;
Spread(n);
int mid=(L+R)>>1;
ll Ans=0;
if(l<=mid) Ans+=Ask_Sum(n<<1,l,r);
if(r>mid) Ans+=Ask_Sum(n<<1|1,l,r);
return Ans;
}
void Add(ll l,ll r,ll n,ll x)
{
ll L=Tree[n].l,R=Tree[n].r;
if(l<=L&&r>=R)
{
Tree[n].add+=x;
Tree[n].minn+=x;
Tree[n].maxn+=x;
Tree[n].sum+=DoSum(n,x);
return ;
}
Spread(n);
int mid=(L+R)>>1;
if(l<=mid) Add(l,r,n<<1,x);
if(r>mid) Add(l,r,n<<1|1,x);
Dodata(n);
}
ll Ask_Max(ll n,ll l,ll r)
{
ll L=Tree[n].l,R=Tree[n].r;
if(l<=L&&r>=R)
return Tree[n].maxn;
Spread(n);
int mid=(L+R)>>1;
ll Ans=-1*(1e+9);
if(l<=mid) Ans=max(Ans,Ask_Max(n<<1,l,r));
if(r>mid) Ans=max(Ans,Ask_Max(n<<1|1,l,r));
return Ans;
}
ll Ask_Min(ll n,ll l,ll r)
{
ll L=Tree[n].l,R=Tree[n].r;
if(l<=L&&r>=R)
return Tree[n].minn;
Spread(n);
int mid=(L+R)>>1;
ll Ans=1e+9;
if(l<=mid) Ans=min(Ans,Ask_Min(n<<1,l,r));
if(r>mid) Ans=min(Ans,Ask_Min(n<<1|1,l,r));
return Ans;
}
void Set(ll n,ll l,ll r,ll x)
{
ll L=Tree[n].l,R=Tree[n].r;
if(l<=L&&r>=R)
{
Tree[n].minn=Tree[n].maxn=Tree[n].add=x;
Tree[n].sum=DoSum(n,x);
Tree[n].flag=1;
return ;
}
Spread(n);
int mid=(L+R)>>1;
if(l<=mid) Set(n<<1,l,r,x);
if(r>mid) Set(n<<1|1,l,r,x);
Dodata(n);
}
int main()
{
string S;
scanf("%lld%lld",&N,&M);
for(ll i=1;i<=N;++i)
scanf("%lld",&a[i]);
build(1,N,1);
for(ll i=1;i<=M;++i)
{
cin>>S;
if(S=="sum") scanf("%lld%lld",&x,&y),
printf("%lld\n",Ask_Sum(1,x,y));
if(S=="add") scanf("%lld%lld%lld",&x,&y,&z),
Add(x,y,1,z);
if(S=="max") scanf("%lld%lld",&x,&y),
printf("%lld\n",Ask_Max(1,x,y));
if(S=="min") scanf("%lld%lld",&x,&y),
printf("%lld\n",Ask_Min(1,x,y));
if(S=="set") scanf("%lld%lld%lld",&x,&y,&z),
Set(1,x,y,z);
}
return 0;
}