【線段樹】序列問題/Can you answer on these queries III
阿新 • • 發佈:2020-08-03
Description
給定長度為N的數列A,以及M條指令,每條指令可能是以下兩種之一:
1、“1 x y”,查詢區間 [x,y] 中的最大連續子段和。
2、“2 x y”,把 A[x] 改成 y。對於每個查詢指令,輸出一個整數表示答案。
Input
第一行兩個整數N,M。
第二行N個整數A[i]。
接下來M行每行3個整數k,x,y,k=1表示查詢(此時如果x>y,請交換x,y),k=2表示修改。
資料範圍
N ≤ 500000,M ≤ 100000
Output
對於每個查詢指令輸出一個整數表示答案。
每個答案佔一行。
Sample Input
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
Sample Output
2
-1
思路
- 線段樹維護:區間緊靠左右兩端的最大連續子段和,區間的總和,區間跨左右子樹的最大連續子段和
- 當前區間的lmax=左子樹lmax和或左子樹區間和+右子樹lmax(rmax同理)
- 極小值-inf注意不能過小,溢位坑死人
程式碼
#include <iostream> #include <cstdio> #define maxn 500005 #define inf 1005 using namespace std; int n,m,v[maxn]; struct fdfdfd{int l,r,lmax,rmax,amax,sum;}a[maxn<<2]; void pushup(int x) { a[x].sum=a[x<<1].sum+a[x<<1|1].sum; a[x].lmax=max(a[x<<1].lmax,a[x<<1].sum+a[x<<1|1].lmax); a[x].rmax=max(a[x<<1|1].rmax,a[x<<1|1].sum+a[x<<1].rmax); a[x].amax=max(max(a[x<<1].amax,a[x<<1|1].amax),a[x<<1].rmax+a[x<<1|1].lmax); } void build(int x,int left,int right) { a[x].l=left; a[x].r=right; if(left==right) { a[x].lmax=a[x].rmax=a[x].amax=a[x].sum=v[left]; return; } int mid=(left+right)>>1; build(x<<1,left,mid); build(x<<1|1,mid+1,right); pushup(x); } void modify(int x,int u,int d) { if(a[x].r<u||a[x].l>u) return; if(a[x].l==u&&a[x].r==u) { a[x].lmax=a[x].rmax=a[x].amax=a[x].sum=d; return; } modify(x<<1,u,d); modify(x<<1|1,u,d); pushup(x); } fdfdfd query(int x,int left,int right) { if(a[x].r<left||a[x].l>right) return (fdfdfd){0,0,-inf,-inf,-inf,-inf}; if(left<=a[x].l&&right>=a[x].r) return a[x]; fdfdfd temp1=query(x<<1,left,right),temp2=query(x<<1|1,left,right),temp; temp.sum=temp1.sum+temp2.sum; temp.lmax=max(temp1.lmax,temp1.sum+temp2.lmax); temp.rmax=max(temp2.rmax,temp2.sum+temp1.rmax); temp.amax=max(max(temp1.amax,temp2.amax),temp1.rmax+temp2.lmax); return temp; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&v[i]); build(1,1,n); while(m--) { int f1,f2,f3; scanf("%d%d%d",&f1,&f2,&f3); if(f1==1) { if(f2>f3) swap(f2,f3); printf("%d\n",query(1,f2,f3).amax); } else modify(1,f2,f3); } return 0; }