1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x43線段樹 單點修改+查詢區間最大子段和

《演算法競賽進階指南》0x43線段樹 單點修改+查詢區間最大子段和

題目連結:https://www.acwing.com/problem/content/246/

線段樹合併線段的時候要更新結點中的ans值,但是這個值的更新依賴於lmax與rmax,這兩個值的更新又依賴於sum,故查詢的時候需要返回的是一個結點,返回代表的區間的資訊。

程式碼:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 500010;
const int inf=0x3f3f3f3f;
int n,m;
struct node{
    int l,r,s,lx,rx,ans;
}t[maxn
*4]; void pushup(int rt){ t[rt].lx=max(t[rt<<1].lx,t[rt<<1].s+t[rt<<1|1].lx); t[rt].rx=max(t[rt<<1|1].rx,t[rt<<1|1].s+t[rt<<1].rx); t[rt].s=t[rt<<1].s+t[rt<<1|1].s; t[rt].ans=max(max(t[rt<<1].ans,t[rt<<1|1].ans),t[rt<<1
].rx+t[rt<<1|1].lx); } void build(int rt,int l,int r){ t[rt].l=l; t[rt].r=r; if(l==r){ scanf("%d",&t[rt].ans); t[rt].lx=t[rt].rx=t[rt].s=t[rt].ans; return ; } int mid=l+r>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); pushup(rt); }
void update(int rt,int pos,int C){ if(t[rt].l==t[rt].r){ t[rt].s=t[rt].lx=t[rt].rx=t[rt].ans=C; return; } int mid=(t[rt].l+t[rt].r)>>1; if(pos<=mid) update(rt<<1,pos,C); else update(rt<<1|1,pos,C); pushup(rt); } node query(int rt,int L,int R){ if(t[rt].l>=L && t[rt].r<=R){ return t[rt]; } node ans1,ans2; int mid=(t[rt].l+t[rt].r)>>1; if(L<=mid && R>mid){ ans1=query(rt<<1,L,R); ans2=query(rt<<1|1,L,R); node ans; ans.s=ans1.s+ans2.s; ans.lx=max(ans1.lx,ans1.s+ans2.lx); ans.rx=max(ans2.rx,ans2.s+ans1.rx); ans.ans=max(max(ans1.ans,ans2.ans),ans1.rx+ans2.lx); return ans; }else if(L>mid){ return query(rt<<1|1,L,R); }else if(R<=mid){ return query(rt<<1,L,R); } } int main(){ cin>>n>>m; build(1,1,n); while(m--){ int t,x,y; scanf("%d%d%d",&t,&x,&y); if(t==1){ if(x>y)swap(x,y); printf("%d\n",query(1,x,y).ans); }else if(t==2){ update(1,x,y); } } return 0; }