另一個畫風的GSS1 - Can you answer these queries I(貓樹)
阿新 • • 發佈:2019-01-14
前言
其實我覺得你看貓錕的解釋也看不懂(主要是還有一些不良心的講解者不講清楚,當然這裡不是針對了qwq)
貓錕連結
Solution
考慮我們的線段樹是個啥玩意?
每一層都是一堆區間疊在一起。
我們在每一個節點維護的又是什麼?
左邊的max,右邊的max,中間的max,還有sum。
那麼我們改變一下:
令\(p_{dps,i}\)表示在深度為\(dps\)的線段樹上\(i\)這個節點所在區間的左邊的max,右邊的max,然後就可以在\(build\)的時候求
再令\(p_{dps,i}\)表示在深度為\(dps\)的線段樹上\(i\)這個節點所在區間的到中間的\(max\),然後也可以在\(build\)
然後就可以\(\Theta(1)\)的詢問就好了。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm> #include<queue> #include<set> #include<map> #include<iostream> using namespace std; #define ll long long #define re register #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout) inline int gi() { int f=1,sum=0;char ch=getchar(); while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return f*sum; } const int N=500010; int pos[N],p[21][N],s[21][N],a[N],Log2[N<<3],n; void build(int o,int l,int r,int dps) { if(l==r) { pos[l]=o; return; } int mid=(l+r)>>1,pre,sm; p[dps][mid]=s[dps][mid]=sm=pre=a[mid]; if(sm<0)sm=0; for(int i=mid-1;i>=l;i--) { sm+=a[i];pre+=a[i]; s[dps][i]=max(s[dps][i+1],pre); p[dps][i]=max(p[dps][i+1],sm); if(sm<0)sm=0; } p[dps][mid+1]=s[dps][mid+1]=sm=pre=a[mid+1]; if(sm<0)sm=0; for(int i=mid+2;i<=r;i++) { sm+=a[i];pre+=a[i]; s[dps][i]=max(s[dps][i-1],pre); p[dps][i]=max(p[dps][i-1],sm); if(sm<0)sm=0; } build(o<<1,l,mid,dps+1); build(o<<1|1,mid+1,r,dps+1); } int query(int l,int r) { if(l==r)return a[l]; int dps=Log2[pos[l]]-Log2[pos[l]^pos[r]]; return max(max(p[dps][l],p[dps][r]),s[dps][l]+s[dps][r]); } int main() { n=gi(); for(int i=1;i<=n;i++)a[i]=gi(); int L=2; while(L<n)L<<=1; for(int i=2;i<=L<<1;i++)Log2[i]=Log2[i>>1]+1; build(1,1,L,1); int m=gi(); while(m--) { int l=gi(),r=gi(); printf("%d\n",query(l,r)); } return 0; }