Can you answer these queries III(luogu)
Description
維護一個長度為n的序列A,進行q次詢問或操作
0 x y:把Ax改為y
1 x y:詢問區間【l,r】的最大子段和
數據范圍:n,q<=5e4,-1e4<=Ai<=1e4;
Solution
線段樹處理區間最大子段和
- res為區間最大子串和
- sum為區間和
- prel和prer分別為從區間左端點和右端點開始的最大子串和
Code
#include <cstdio> #include <cstdlib> #include <algorithm>
#define ll long long
using namespace std; const int N=5e4+10; struct node { ll sum,res,prel,prer; int l,r,lc,rc; }f[N*2],t; int opt,tot,rt,n,q,x,y; ll d[N]; void push_up(int g) { int lc=f[g].lc,rc=f[g].rc; if(!lc) return ; f[g].sum=f[lc].sum+f[rc].sum; f[g].prel=max(f[lc].prel,f[lc].sum+f[rc].prel); f[g].prer=max(f[rc].prer,f[rc].sum+f[lc].prer); f[g].res=max(max(f[lc].res,f[rc].res),f[lc].prer+f[rc].prel); } void build(int &g,int l,int r) { g=++tot; f[g].l=l,f[g].r=r; if(l==r) { f[g].sum=f[g].prel=f[g].prer=f[g].res=d[l]; return ; } int mid=(l+r)>>1; build(f[g].lc,l,mid),build(f[g].rc,mid+1,r); push_up(g); } void change(int g,int x,int y) { if(f[g].l==f[g].r) f[g].sum=f[g].res=f[g].prel=f[g].prer=y; else { int mid=(f[g].l+f[g].r)>>1; if(x<=mid) change(f[g].lc,x,y); else change(f[g].rc,x,y); push_up(g); } } ll get(int g,int l,int r,node &a) { if(f[g].l==l && f[g].r==r) { a=f[g]; return a.res; } else { int mid=(f[g].l+f[g].r)>>1; if(r<=mid) return get(f[g].lc,l,r,a); else if(l>mid) return get(f[g].rc,l,r,a); else { node b,c; get(f[g].lc,l,mid,b); get(f[g].rc,mid+1,r,c); a.sum=b.sum+c.sum; a.prel=max(b.prel,b.sum+c.prel); a.prer=max(c.prer,c.sum+b.prer); a.res=max(max(b.res,c.res),b.prer+c.prel); return a.res; } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&d[i]); build(rt,1,n); scanf("%d",&q); while(q--) { scanf("%d%d%d",&opt,&x,&y); if(!opt) change(rt,x,y); else printf("%lld\n",get(rt,x,y,t)); } return 0; }
維護一個長度為 n 的序列 A,進行 m 次詢問或操作:
0 x y
:將 Ax 單調修改為 y1 x y
:求出 max{∑k=ijAk}(x≤i≤j≤y)。
數據范圍:N,M≤5×104,∣Ai∣≤104