链接
背景
(USACO) (2015) (Dec) (Platinum) (T3) , (Luogu) (P3130/BZOJ4392)
题意
给定 (n) 个数组成的序列 (a_i) ,以及 (q) 次询问。每次询问先给出一个字符 (op) 表示操作类型, (op='M') 表示查询给定区间 ([l,r]) 的最小值; (op='S') 表示查询给定区间 ([l,r]) 的和; (op='P') 表示将给定区间 ([l,r]) 的值全都增加 (val) 。
解法
线段树区间修改、区间查询模板。
注意最小值的更新信息方法是直接加。
代码
$View$ $Code$
```cpp
#include
using namespace std;
inline int read()
{
int ret=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ret=(ret<<1)+(ret<<3)+ch-'0';
ch=getchar();
}
return ret*f;
}
int n,q,a[200005],l,r,val;
char op;
struct SegmentTree
{
int l,r,add;
long long minn,sum;
}t[800005];
void build(int pos,int l,int r)
{
t[pos].l=l;
t[pos].r=r;
if(l==r)
{
t[pos].minn=a[l];
t[pos].sum=a[l];
return;
}
int mid=(l+r)/2;
build(pos<<1,l,mid);
build(pos<<1|1,mid+1,r);
t[pos].sum=t[pos<<1].sum+t[pos<<1|1].sum;
t[pos].minn=min(t[pos<<1].minn,t[pos<<1|1].minn);
}
inline void spread(int pos)
{
if(t[pos].add)
{
t[pos<<1].sum+=1ll*t[pos].add*(t[pos<<1].r-t[pos<<1].l+1);
t[pos<<1|1].sum+=1ll*t[pos].add*(t[pos<<1|1].r-t[pos<<1|1].l+1);
t[pos<<1].minn+=t[pos].add;
t[pos<<1|1].minn+=t[pos].add;
t[pos<<1].add+=t[pos].add;
t[pos<<1|1].add+=t[pos].add;
t[pos].add=0;
}
}
void modify(int pos,int l,int r,int val)
{
if(l<=t[pos].l&&t[pos].r<=r)
{
t[pos].sum+=1ll*val*(t[pos].r-t[pos].l+1);
t[pos].minn+=val;
t[pos].add+=val;
return;
}
spread(pos);
int mid=(t[pos].l+t[pos].r)/2;
if(l<=mid)
modify(pos<<1,l,r,val);
if(mid