长度为\(n\)(\(n \le 10^5\))的数列\(a_i\),进行\(m\)次操做(\(m \le 10^5\))支持两种操做:node
\(0 \; i \; val :\) 将\(a_i\)修改成\(val\)ios
\(1 \; l \; r \; k:\) 询问区间\([l,r]\)里选出至多\(k\)个不相交的子段和的最大值。(\(\sum_{}k \le 10^5\))ui
先考虑几个简单的问题:this
若\(k=1\),则该问题就是\(GSS3\)。spa
若没有修改操做,而且操做\(2\)中\(l=一、r=n\),则是一个经典的最大\(k\)段子段和问题。code
问题\(1\)不用多说,用线段树维护\(Lmax、Rmax、Sum、Ans\)便可。get
对于问题\(2\),考虑贪心,取\(k\)次,每次都选择最大子段和。it
然而,一个数最多只能被选一次,因此每选一次后要删除它对后续操做的影响。io
容易发现一个结论:咱们每次把所选区间内的数进行取反操做便可删除影响(即选不到这个数)。class
这一点能够根据费用流的思想取证实,这里就再也不赘述。
如今咱们考虑如何高效的模拟这个过程。
首先,这个过程能与问题\(1\)的线段树解法相结合呢?
答案是确定的。
咱们发现,无论多少次取负,一个位置的数只有两种可能(一正一负),因此咱们能够维护两颗线段树。
合并时分别合并,取负时找到对应区间,交换二者信息 并打上标记便可。
再结合问题\(1\)的单点修改,这个问题就能够获得完美解决。
#include<cstdio> #include<algorithm> #include<queue> #include<stack> using namespace std; #define ll long long #define rg register struct ios{ template<typename TP> inline ios operator >> (TP &x) { TP f=1;x=0;rg char c=getchar(); for(;c>'9' || c<'0';c=getchar()) if(c=='-') f=-1; for(;c>='0' && c<='9';c=getchar()) x=(x<<3)+(x<<1)+(c^'0'); x*=f; return *this; } template<typename TP> inline ios operator << (TP x) { int top=0,s[66]; if(x<0) x=-x,putchar('-'); if(!x) putchar('0'); while(x) s[++top]=x%10+'0',x/=10; while(top) putchar(s[top--]); return *this; } inline ios operator << (char s) { putchar(s); return *this; } }io; #define ls rt<<1 #define rs rt<<1|1 #define lson l,mid,ls #define rson mid+1,r,rs const int N=1e5+5; int n,m,a[N]; bool Tag[N<<2]; struct node{ int Lmax,Rmax,Ans,Sum; /* Lmax:区间从左端开始的最大子段和 Rmax:区间从右端开始的最大子段和 Sum:区间和 Ans:区间最大子段和 */ int L,R,Ansl,Ansr; /* L:区间左端最长子段的右端点 R:区间右端最长子段的左端点 ↓↓↓↓↓↓↓↓↓↓维护↓↓↓↓↓↓↓↓↓↓ Ansl:当前区间的最长子段的左端点 Ansr:当前区间的最长子段的右端点 建一正一负两颗线段树 但一段区间在两种状况下的最长子段和的值和对应的位置不必定相同 因此要维护Ansl、Ansr 维护Ansl、Ansr就要用到L、R */ inline node(rg int pos=0,rg int val=0) {L=R=Ansl=Ansr=pos,Lmax=Rmax=Ans=Sum=val;} }t[2][N<<2]; stack<node>q; inline node operator + (node A,node B) { node Ans; if(A.Lmax>A.Sum+B.Lmax) Ans.Lmax=A.Lmax,Ans.L=A.L; else Ans.Lmax=A.Sum+B.Lmax,Ans.L=B.L; //容易发现一个区间的Lmax只多是左儿子的Lmax或右儿子的Lmax+左儿子的区间和 if(B.Rmax>A.Rmax+B.Sum) Ans.Rmax=B.Rmax,Ans.R=B.R; else Ans.Rmax=B.Sum+A.Rmax,Ans.R=A.R; //同上 Ans.Sum=A.Sum+B.Sum; if(A.Ans>B.Ans) Ans.Ans=A.Ans,Ans.Ansl=A.Ansl,Ans.Ansr=A.Ansr; else Ans.Ans=B.Ans,Ans.Ansl=B.Ansl,Ans.Ansr=B.Ansr; if(A.Rmax+B.Lmax>Ans.Ans) Ans.Ans=A.Rmax+B.Lmax,Ans.Ansl=A.R,Ans.Ansr=B.L; return Ans; } inline void pushup(int rt) { t[0][rt]=t[0][ls]+t[0][rs]; t[1][rt]=t[1][ls]+t[1][rs]; } inline void build(int l,int r,int rt) { // io<<l<<' '<<r<<' '<<rt<<'\n'; if(l==r) { t[0][rt]=node(l,a[l]); t[1][rt]=node(l,-a[l]); return; } int mid=(l+r)>>1; build(lson),build(rson); pushup(rt); } inline void Get(int rt) { swap(t[0][rt],t[1][rt]); Tag[rt]^=1; } inline void update(int p,int val,int l,int r,int rt) { // io<<l<<' '<<r<<' '<<rt<<'\n'; if(l==r) { t[0][rt]=node(l,val); t[1][rt]=node(l,-val); return; } if(Tag[rt]) { Get(ls),Get(rs); Tag[rt]=0; } int mid=(l+r)>>1; if(p<=mid) update(p,val,lson); else update(p,val,rson); pushup(rt); } inline void Modify(int L,int R,int l,int r,int rt)//区间取反 { if(L<=l && r<=R) { Get(rt); return; } if(Tag[rt]) { Get(ls),Get(rs); Tag[rt]=0; } int mid=(l+r)>>1; if(L<=mid) Modify(L,R,lson); if(R>mid) Modify(L,R,rson); pushup(rt); } inline node query(int L,int R,int l,int r,int rt)//查询能够覆盖区间[L,R]的节点的信息 { if(L<=l && r<=R) return t[0][rt]; if(Tag[rt]) { Get(ls),Get(rs); Tag[rt]=0; } int mid=(l+r)>>1; if(R<=mid) return query(L,R,lson); else if(L>mid) return query(L,R,rson); else return query(L,mid,lson)+query(mid+1,R,rson); } int main() { // freopen("CF280D.in","r",stdin); io>>n; for(rg int i=1;i<=n;++i) io>>a[i]; build(1,n,1),io>>m; for(rg int _=1,op,l,r,k;_<=m;++_) { io>>op; if(!op) { io>>l>>r; update(l,r,1,n,1); } else { io>>l>>r>>k;int ans=0; for(rg int i=1;i<=k;++i) { node Ans=query(l,r,1,n,1); if(Ans.Ans<=0) break; // io<<Ans.Ans<<' '; ans+=Ans.Ans,q.push(Ans);//记录被影响的区间,查询完成后再撤销 Modify(Ans.Ansl,Ans.Ansr,1,n,1); } // io<<'\n'; io<<ans<<'\n'; while(!q.empty()) { node t=q.top();q.pop(); Modify(t.Ansl,t.Ansr,1,n,1); } } } return 0; } /* 15 -4 8 -3 -10 10 4 -7 -7 0 -6 3 8 -10 7 2 15 1 3 9 2 0 5 -10 1 3 9 2 */ /* 15 -4 8 -3 -10 10 4 -7 -7 0 -6 3 8 -10 7 2 15 1 3 9 2 1 6 12 1 0 6 5 0 10 -7 1 4 9 1 1 7 9 1 0 10 -3 1 4 10 2 1 3 13 2 1 4 11 2 0 15 -9 0 13 -9 0 11 -10 1 5 14 2 1 6 12 1 */ /* 20 -5 -1 -9 -6 4 -5 6 1 5 -3 6 -3 10 1 4 -10 -10 -9 10 -6 20 0 19 0 1 1 14 3 1 8 20 4 1 9 11 1 1 17 19 1 0 13 4 0 9 7 1 2 11 2 0 20 -8 1 8 19 1 0 2 3 1 6 11 1 0 6 -10 1 8 13 1 1 9 15 1 0 17 -8 1 3 13 1 1 1 14 4 0 17 0 1 7 19 1 */