题目传送门:https://www.luogu.org/problemnew/show/P3130
题意:
有n个数,m个操作,现在对于每一个操作:
[M]:询问x~y区间的最小值;
[P]:x~y区间加上z;
[S]:x~y的区间和。
思路:
线段树裸题。
注意:
1.findmin中不能用手写三目运算符,时间复杂度会变为O(n^2*logn),因为lazy优化被改为0,全部废掉,变为暴力;
2.要用long long。
前前后后坑了我一个多小时。
代码:
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
struct node{int n,l,r,lc,rc;LL d1,d2,lazy;} tr[500000];
int n,m,len=0;
LL MIN(LL x,LL y)
{
return x<y?x:y;
}
void build(int l,int r)
{
int now=++len,mid=(l+r)>>1;
tr[now].l=l;
tr[now].r=r;
tr[now].d1=tr[now].d2=tr[now].lazy=0;
tr[now].lc=tr[now].rc=-1;
tr[now].n=r-l+1;
if(l<r)
{
tr[now].lc=len+1; build(l,mid);
tr[now].rc=len+1; build(mid+1,r);
}
}
void update(int now)
{
if(tr[now].lazy)
{
int lc=tr[now].lc,rc=tr[now].rc;
if(lc!=-1) tr[lc].lazy+=tr[now].lazy,tr[lc].d1+=tr[lc].n*tr[now].lazy,tr[lc].d2+=tr[now].lazy;
if(rc!=-1) tr[rc].lazy+=tr[now].lazy,tr[rc].d1+=tr[rc].n*tr[now].lazy,tr[rc].d2+=tr[now].lazy;
tr[now].lazy=0;
}
}
void change(int now,int l,int r,int k)
{
if(l==tr[now].l&&r==tr[now].r)
{
tr[now].lazy+=k;
tr[now].d1+=(LL)tr[now].n*k;
tr[now].d2+=k;
return;
}
update(now);
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) change(lc,l,r,k);
else if(l>mid) change(rc,l,r,k);
else change(lc,l,mid,k),change(rc,mid+1,r,k);
tr[now].d1=tr[lc].d1+tr[rc].d1;
tr[now].d2=MIN(tr[lc].d2,tr[rc].d2);
}
LL findsum(int now,int l,int r)
{
if(l==tr[now].l&&r==tr[now].r) return tr[now].d1;
update(now);
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) return findsum(lc,l,r);
else if(l>mid) return findsum(rc,l,r);
else return findsum(lc,l,mid)+findsum(rc,mid+1,r);
}
LL findmin(int now,int l,int r)
{
if(l==tr[now].l&&r==tr[now].r) return tr[now].d2;
update(now);
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) return findmin(lc,l,r);
else if(l>mid) return findmin(rc,l,r);
else return MIN(findmin(lc,l,mid),findmin(rc,mid+1,r));
}
int main()
{
int x,y;
LL z;
char s[5];
scanf("%d %d",&n,&m);
build(1,n);
for(int i=1;i<=n;i++)
{
scanf("%d",&z);
change(1,i,i,z);
}
for(int i=1;i<=m;i++)
{
scanf("%s %d %d",s+1,&x,&y);
if(x>y) swap(x,y);
switch(s[1])
{
case 'M':printf("%lld\n",findmin(1,x,y));break;
case 'P':scanf("%d",&z);change(1,x,y,z);break;
case 'S':printf("%lld\n",findsum(1,x,y));break;
}
}
}