1. 程式人生 > >2018.10.16 spoj Can you answer these queries V(線段樹)

2018.10.16 spoj Can you answer these queries V(線段樹)

傳送門 線段樹經典題。 就是讓你求左端點在[l1,r1][l1,r1]之間,右端點在[l2,r2][l2,r2]之間且滿足l1l2,r1r2l1\le l2,r1 \le r2的最大子段和。

直接分類討論就行了。 如果兩個區間不相交的話,答案就是rmax(l1,l2)+sum(l2+1,l21)+lmax(l2,r2)rmax(l1,l2)+sum(l2+1,l2-1)+lmax(l2,r2)。 如果相交的話,討論一下就是max(max(rmax(l1,l2)+

lmax(l2,r2)val[l2],rmax(l1,r1)+lmax(r1,r2)val[r1]),midmax(l2,r1))max(max(rmax(l1,l2)+lmax(l2,r2)-val[l2],rmax(l1,r1)+lmax(r1,r2)-val[r1]),midmax(l2,r1))

程式碼:

#include<bits/stdc++.h>
#define lc (p<<1)
#define
rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1) #define N 10005 using namespace std; inline int read(){ int ans=0,w=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();} while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans*w; } int n,m,a[N]
,T_T; struct Node{int l,r,ls,rs,ms,sum;}T[N<<2]; inline Node operator+(const Node&a,const Node&b){ Node ret; ret.l=a.l,ret.r=b.r,ret.sum=a.sum+b.sum; ret.ls=max(a.ls,a.sum+b.ls); ret.rs=max(b.rs,b.sum+a.rs); ret.ms=max(max(a.ms,b.ms),a.rs+b.ls); return ret; } inline void build(int p,int l,int r){ T[p].l=l,T[p].r=r; if(l==r){T[p].ls=T[p].rs=T[p].ms=T[p].sum=a[l];return;} build(lc,l,mid),build(rc,mid+1,r),T[p]=T[lc]+T[rc]; } inline Node query(int p,int ql,int qr){ if(ql>T[p].r||qr<T[p].l)return (Node){T[p].l,T[p].r,0,0,0,0}; if(ql<=T[p].l&&T[p].r<=qr)return T[p]; if(qr<=mid)return query(lc,ql,qr); if(ql>mid)return query(rc,ql,qr); return query(lc,ql,mid)+query(rc,mid+1,qr); } int main(){ T_T=read(); while(T_T--){ n=read(); for(int i=1;i<=n;++i)a[i]=read(); build(1,1,n),m=read(); while(m--){ int l1=read(),r1=read(),l2=read(),r2=read(); if(r1<l2){ Node ansl=query(1,l1,r1),ansm=query(1,r1+1,l2-1),ansr=query(1,l2,r2); printf("%d\n",ansl.rs+ansm.sum+ansr.ls); } else{ int ans=query(1,l2,r1).ms; if(l1<l2)ans=max(ans,query(1,l1,l2).rs+query(1,l2,r2).ls-a[l2]); if(r2>r1)ans=max(ans,query(1,l1,r1).rs+query(1,r1,r2).ls-a[r1]); printf("%d\n",ans); } } } return 0; }