思路:
动态开节点线段树;
等差序列求和于取大,是两个独立的子问题;
所以,建两颗线段树分开维护;
求和:等差数列的首项和公差直接相加即可;
取大:
对于线段树每个节点储存一条斜率为等差数列公差的线段;
当添加线段到已有线段的节点,下传一条线段,当前节点留下一条线段;
当要添加的线段完全覆盖或者被覆盖当前节点储存的线段时,选择更新或者不更新;
单点查询时,从根节点到叶节点的路径上去最大值;
来,上代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define INF (1LL<<62) struct TreeNodeType { ll a,b; bool if_; struct TreeNodeType *lc,*rc; TreeNodeType() { lc=NULL,rc=NULL,if_=false,a=0,b=0; } }; ll n,m; inline void in(ll &now) { ll if_z=1;now=0; char Cget=getchar(); while(Cget>'9'||Cget<'0') { if(Cget=='-') if_z=-1; Cget=getchar(); } while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } now*=if_z; } class SumTreeType { public: struct TreeNodeType *root; SumTreeType(){} inline void tree_down(TreeNodeType *&now,ll l,ll r) { if(now->lc==NULL) now->lc=new TreeNodeType; if(now->rc==NULL) now->rc=new TreeNodeType; now->lc->a+=now->a,now->lc->b+=now->b; now->rc->a+=now->a+((l+r>>1)-l+1)*now->b,now->rc->b+=now->b; now->a=0,now->b=0; } void tree_add(TreeNodeType *&now,ll l,ll r,ll li,ll ri,ll a,ll b) { if(now==NULL) now=new TreeNodeType; if(l==li&&r==ri) { now->a+=a,now->b+=b; return ; } ll mid=l+r>>1; if(now->a!=0&&now->b!=0) tree_down(now,l,r); if(li>mid) tree_add(now->rc,mid+1,r,li,ri,a,b); else if(ri<=mid) tree_add(now->lc,l,mid,li,ri,a,b); else { tree_add(now->lc,l,mid,li,mid,a,b); tree_add(now->rc,mid+1,r,mid+1,ri,a+(mid-li+1)*b,b); } } ll tree_query(TreeNodeType *&now,ll l,ll r,ll to) { if(now==NULL) return 0; if(l==r) return now->a; if(now->a!=0||now->b!=0) tree_down(now,l,r); ll mid=l+r>>1; if(to<=mid) return tree_query(now->lc,l,mid,to); else return tree_query(now->rc,mid+1,r,to); } }; class SumTreeType ai; class MaxTreeType { public: ll X; bool op; struct TreeNodeType *root; MaxTreeType(){} inline double com(ll a1,ll b1,ll a2,ll b2) { if(a1==a2) return 0; return (double)(a1-a2)/(double)(b2-b1); } void tree_down(TreeNodeType *&now,ll l,ll r,ll a,ll b) { if(now==NULL) { now=new TreeNodeType; now->if_=true; now->a=a,now->b=b; return ; } if(!now->if_) { now->a=a,now->b=b,now->if_=true; return ; } double xx=com(now->a-l*now->b,now->b,a-l*b,b),mid=l+r>>1; if(xx<=l||xx>=r) { if((mid-l)*b+a>(mid-l)*now->b+now->a) now->a=a,now->b=b; return ; } if(xx<=mid) { if(now->b<b) { tree_down(now->lc,l,mid,now->a,now->b); now->a=a,now->b=b,now->if_=true; } else tree_down(now->lc,l,mid,a,b); } else { if(now->b<b) tree_down(now->rc,mid+1,r,a+(mid-l+1)*b,b); else { tree_down(now->rc,mid+1,r,now->a+(mid-l+1)*now->b,now->b); now->a=a,now->b=b,now->if_=true; } } } void tree_add(TreeNodeType *&now,ll l,ll r,ll li,ll ri,ll a,ll b) { if(now==NULL) now=new TreeNodeType; if(l==li&&r==ri) { if(!now->if_) { now->if_=true; now->a=a,now->b=b; } else tree_down(now,l,r,a,b); return ; } ll mid=l+r>>1; if(ri<=mid) tree_add(now->lc,l,mid,li,ri,a,b); else if(li>mid) tree_add(now->rc,mid+1,r,li,ri,a,b); else { tree_add(now->lc,l,mid,li,mid,a,b); tree_add(now->rc,mid+1,r,mid+1,ri,a+(mid-li+1)*b,b); } } void tree_query(TreeNodeType *&now,ll l,ll r,ll to) { if(now==NULL) return ; if(now->if_) X=max(X,now->a+(to-l)*now->b); if(l==r) return ; ll mid=l+r>>1; if(to<=mid) tree_query(now->lc,l,mid,to); else tree_query(now->rc,mid+1,r,to); } }; class MaxTreeType bi; int main() { in(n),in(m);ll op,u,v,a,b; for(ll i=1;i<=m;i++) { in(op); if(op==1) { in(u),in(v),in(b),in(a); bi.tree_add(bi.root,1,n,u,v,a,b); } else if(op==2) { in(u),in(v),in(b),in(a); ai.tree_add(ai.root,1,n,u,v,a,b); } else if(op==3) { in(u); bi.X=-INF; bi.tree_query(bi.root,1,n,u); if(bi.X==-INF) printf("NA "); else printf("%lld ",bi.X+ai.tree_query(ai.root,1,n,u)); } } return 0; }