1. 程式人生 > >[SP1557]GSS2 - Can you answer these queries II

[SP1557]GSS2 - Can you answer these queries II

常用 最大子段和 bool 修改 == 意義 一次 合並 ans

題意不過只是比GSS1多了幾個字而已,難度卻把GSS1甩得望塵莫及。

給出n個數,q次詢問,求最大子段和(可為空),相同的數只算一次

說到相同的只算一次這一條件,有點像[SDOI2009]HH的項鏈,但是本題不再是簡簡單單的統計個數,而是求最大子段和。

由於題目條件,GSS1的合並Lmax,Midmax,Rmax的方法以不再適用,我們必須另辟蹊徑。

做題經驗告訴我們,要處理有關區間去重的問題時,我們常用到離線算法,本題亦是如此。

仍然是用線段樹,只不過我們要把序列中的元素一個個添加進去。

將所有詢問按r排序,在最終處理詢問到以r為區間右邊界時,將a[r]添加到線段樹。

線段樹每個節點維護4個值,sum,hismax,sumtag,hismaxtag。

假設現在處理到以y為區間右邊界的詢問了,那麽,對於葉結點

sum表示從這個葉結點所對應的原序列的下標x到y的所有元素和,及a[x]+a[x+1]+a[x+2]+...+a[y],

hismax表示sum的歷史最大值(最小為0)。

對於內部節點

sum表示左右兒子的sum的最大值,

hismax表示左右兒子的hismax的最大值。

另外的,利用sumtag和hismaxtag作為延遲標記實現單次修改/詢問O(logn)復雜度,具體意義參考代碼。

如何向線段樹添加元素?

記錄序列中第i個元素上一個相同元素的位置pre[i],添加元素是[pre[i]+1,i]區間加a[i]即可。

如何查詢?

查詢[l,r]的hismax。

要特別註意pushdown()函數的更新順序,非常容易弄錯。

還有各種實現細節,一定要特別註意。

線段樹不可多得的好題。

代碼:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 typedef long long LL;
 8 inline LL read(){
 9     LL x=0,f=1;char
ch=getchar(); 10 while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();} 11 while(ch>=0&&ch<=9){x=(x<<3)+(x<<1)+ch-0;ch=getchar();} 12 return x*f; 13 } 14 const int MAXN=100005; 15 struct Node{ 16 LL sum,hix,stag,htag; 17 Node(){ 18 sum=hix=stag=htag=0; 19 } 20 friend Node operator + (Node lf,Node rt){ 21 Node res; 22 res.sum=max(lf.sum,rt.sum); 23 res.hix=max(lf.hix,rt.hix); 24 return res; 25 } 26 }b[MAXN*4]; 27 struct Qst{ 28 int l,r,id; 29 }q[MAXN]; 30 bool cmp(Qst x,Qst y){ 31 return x.r<y.r; 32 } 33 int n,m,cur[MAXN*2],pre[MAXN],ql,qr;LL a[MAXN],ans[MAXN],k; 34 #define mid ((l+r)>>1) 35 #define lc (o<<1) 36 #define rc ((o<<1)|1) 37 void pushup(int o){ 38 b[o]=b[lc]+b[rc]; 39 } 40 void pushdown(int o){//註意更新先後順序 41 b[lc].hix=max(b[lc].hix,b[lc].sum+b[o].htag); 42 b[rc].hix=max(b[rc].hix,b[rc].sum+b[o].htag); 43 b[lc].sum+=b[o].stag; 44 b[rc].sum+=b[o].stag; 45 b[lc].htag=max(b[lc].htag,b[lc].stag+b[o].htag); 46 b[rc].htag=max(b[rc].htag,b[rc].stag+b[o].htag); 47 b[lc].stag+=b[o].stag; 48 b[rc].stag+=b[o].stag; 49 b[o].stag=b[o].htag=0; 50 } 51 void upd(int o,int l,int r){ 52 if(ql<=l&&r<=qr){ 53 b[o].sum+=k; 54 b[o].hix=max(b[o].hix,b[o].sum); 55 b[o].stag+=k; 56 b[o].htag=max(b[o].htag,b[o].stag); 57 return; 58 } 59 pushdown(o); 60 if(mid>=ql) upd(lc,l,mid); 61 if(mid<qr) upd(rc,mid+1,r); 62 pushup(o); 63 } 64 Node query(int o,int l,int r){ 65 if(ql<=l&&r<=qr) return b[o]; 66 pushdown(o); 67 if(mid<ql) return query(rc,mid+1,r); 68 else if(mid>=qr) return query(lc,l,mid); 69 else return query(lc,l,mid)+query(rc,mid+1,r); 70 } 71 int main(){ 72 n=read(); 73 for(int i=1;i<=n;i++){ 74 a[i]=read(); 75 pre[i]=cur[a[i]+(int)1e5]; 76 cur[a[i]+(int)1e5]=i; 77 } 78 m=read(); 79 for(int i=1;i<=m;i++){ 80 q[i].l=read(),q[i].r=read(); 81 q[i].id=i; 82 } 83 sort(q+1,q+m+1,cmp); 84 int j=1; 85 for(int i=1;i<=n;i++){ 86 ql=pre[i]+1,qr=i,k=a[i]; 87 upd(1,1,n); 88 for(;j<=m&&q[j].r<=i;j++){ 89 ql=q[j].l,qr=q[j].r; 90 ans[q[j].id]=query(1,1,n).hix; 91 } 92 } 93 for(int i=1;i<=m;i++) 94 printf("%lld\n",ans[i]); 95 return 0; 96 }

[SP1557]GSS2 - Can you answer these queries II