两种操作可以分开处理。
第一种操作:开一棵线段树,线段树上每个节点记录一个影响整个区间的等差数列。
第二种操作直接打标记就好了,复杂度O(logn)
这题真心烦。理解了一个上午,写了一个下午,搞笑了一个晚上,又调了一个上午才A。
其实理解难度还是不大的,只是没人愿意好好讲。但是写起来细节真的很多。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pll pair<LL,LL>
#define mkp make_pair
#define X first
#define Y second
#define N 400005
#define NN 10000000
#define inf 4611686018427387904LL
#define eps 0.000001
int n;
int rt1,id1,lc1[NN],rc1[NN];LL a1[NN],d1[NN],MAX;
int rt2,id2,lc2[NN],rc2[NN];LL a2[NN],d2[NN],lza[NN],lzd[NN],SUM;
int read(){
int x=0;char ch=G;bool flg=0;
for(;ch<48||ch>57;ch=G)flg|=ch==45;
for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
return flg?-x:x;
}
int dcmp(double x){
if(fabs(x)<eps)return 0;
return x<0?-1:1;
}
double Ict(LL a,LL d,LL a0,LL d0){
return (double)(a0-a)/(d-d0);
}
void Add(LL a,LL d,int l,int r,int&num,int fa){
LL &a0=a1[num],&d0=d1[num],b0=a0+d0*(r-l),b=a+d*(r-l);
if(a0>=a&&b0>=b)return;
if(a>=a0&&b>=b0){a0=a;d0=d;return;}
double tmp=Ict(a,d,a0,d0);int mid=l+r>>1;
if(dcmp(l+tmp-mid)<=0){
if(b>b0){
if(!lc1[num]){a1[lc1[num]=++id1]=a;d1[lc1[num]]=d;}
Add(a0,d0,l,mid,lc1[num],num);a0=a;d0=d;
}
else{
if(!lc1[num]){a1[lc1[num]=++id1]=a0;d1[lc1[num]]=d0;}
Add(a,d,l,mid,lc1[num],num);
}
}
else{
if(a>a0){
if(!rc1[num]){a1[rc1[num]=++id1]=a+(mid+1-l)*d;d1[rc1[num]]=d;}
Add(a0+(mid+1-l)*d0,d0,mid+1,r,rc1[num],num);a0=a;d0=d;
}
else{
if(!rc1[num]){a1[rc1[num]=++id1]=a0+(mid+1-l)*d0;d1[rc1[num]]=d0;}
Add(a+(mid+1-l)*d,d,mid+1,r,rc1[num],num);
}
}
}
void add1(int L,int R,LL a,LL d,int l,int r,int&num,int fa){
if(L<=l&&r<=R){
Add(a+(l-L)*d,d,l,r,num,fa);return;
}
int mid=l+r>>1;
if(R>mid){
if(!rc1[num]){a1[rc1[num]=++id1]=a1[num]+(mid+1-l)*d1[num];d1[rc1[num]]=d1[num];}
add1(L,R,a,d,mid+1,r,rc1[num],num);
}
if(L<=mid){
if(!lc1[num]){a1[lc1[num]=++id1]=a1[num];d1[lc1[num]]=d1[num];}
add1(L,R,a,d,l,mid,lc1[num],num);
}
}
void pd(int num,int x){
if(lc2[num]){
a2[lc2[num]]+=lza[num];
lza[lc2[num]]+=lza[num];
d2[lc2[num]]+=lzd[num];
lzd[lc2[num]]+=lzd[num];
}
if(rc2[num]){
a2[rc2[num]]+=lza[num]+lzd[num]*(x+1>>1);
lza[rc2[num]]+=lza[num]+lzd[num]*(x+1>>1);
d2[rc2[num]]+=lzd[num];
lzd[rc2[num]]+=lzd[num];
}
lza[num]=lzd[num]=0;
}
void add2(int L,int R,LL a,LL d,int l,int r,int &num,int fa){
if(L<=l&&r<=R){
a2[num]+=a+=(l-L)*d;lza[num]+=a;d2[num]+=d;lzd[num]+=d;return;
}
int mid=l+r>>1;pd(num,r-l+1);
if(R>mid){
if(!rc2[num]){a2[rc2[num]=++id2]=a2[num]+(mid+1-l)*d2[num];d2[rc2[num]]=d2[num];}
add2(L,R,a,d,mid+1,r,rc2[num],num);
}
if(L<=mid){
if(!lc2[num]){a2[lc2[num]=++id2]=a2[num];d2[lc2[num]]=d2[num];}
add2(L,R,a,d,l,mid,lc2[num],num);
}
}
void query1(int x,int l,int r,int num){
if(!num)return;
MAX=max(MAX,a1[num]+(x-l)*d1[num]);
int mid=l+r>>1;
if(x>mid)query1(x,mid+1,r,rc1[num]);
else query1(x,l,mid,lc1[num]);
}
void query2(int x,int l,int r,int num){
if(!num)return;
if(l==r){SUM=a2[num];return;}
pd(num,r-l+1);
int mid=l+r>>1;
if(x>mid)query2(x,mid+1,r,rc2[num]);
else query2(x,l,mid,lc2[num]);
if(SUM==-inf)SUM=a2[num]+(x-l)*d2[num];
}
int main(){
n=read();
int Q=read(),o,l,r,x;LL a,d;
a1[rt1=id1=rt2=id2=1]=-inf;
while(Q--){
o=read();
if(o==3){
MAX=-inf;query1(x=read(),1,n,rt1);
if(MAX==-inf)puts("NA");
else{
SUM=-inf;query2(x,1,n,rt2);
printf("%lld\n",SUM+MAX);
}
}
else{
l=read();r=read();d=read();a=read();
if(o==1)add1(l,r,a,d,1,n,rt1,0);
else add2(l,r,a,d,1,n,rt2,0);
}
}
return 0;
}