GSS2 Can you answer these queries II(線段樹)
阿新 • • 發佈:2019-01-22
題目大意:給你一個長度為n的陣列,有q次詢問,每次詢問給出一個區間[X,Y],要你找出 MAX:{sum[i,j]} (X<=i<=j<=Y),同時區間求和的時候,如果一個數出現了多次,那麼計算和的時候只計算一次。
題目思路:通常我們都是用線段樹來解決區間求最大子段和問題,但這題需要解決數字重複的問題。
要解決這個問題可以進行離線操作,用一個vis[a[i]](a[i]可能為負數,所以儲存的時候記得加上100000)陣列來儲存a[i]這個數上一次出現的位置,然後每次更新和的時候只用將[vis[a[i]],i]這個區間加上a[i]就可以了。
然後將詢問按區間右端點進行排序,一邊更新,一邊求解。
線段樹中儲存4個值
MAX:儲存當前區間的最優解
sum:儲存當前區間的最大值
lazy:懶惰標記,用來記錄下傳的值
prelazy:第二個懶惰標記,記錄下傳的最大值
這裡為什麼要用兩個懶惰標記呢,第一個懶惰標記是用來正常的區間更新操作的,而第二個懶惰標記是用來更新最優解的,比如一個區間中下傳了-5,但是在他的左兒子中有個懶惰標記為5,對於他的左兒子來說,直接加5才是最優解。
具體實現看程式碼:
#include <bits/stdc++.h> #define fi first #define se second #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pb push_back #define MP make_pair #define debug(x) cout<<"["<<x<<"]"<<endl #define FIN freopen("in.txt","r",stdin) using namespace std; typedef long long LL; typedef pair<int,int>pii; const int M=1e5; const int MX=2e5+7; int n,m; int a[MX]; int MAX[MX<<2],lazy[MX<<2],prelazy[MX<<2],sum[MX<<2]; int vis[MX]; struct que{ int l,r,id; LL ans; bool operator<(const que &que1)const{ return r<que1.r; } }q[MX]; void push_up(int rt){ MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); sum[rt]=max(sum[rt<<1],sum[rt<<1|1]); } void push_down(int rt){ if(lazy[rt] || prelazy[rt]){ prelazy[rt<<1]=max(prelazy[rt<<1],prelazy[rt]+lazy[rt<<1]); MAX[rt<<1]=max(MAX[rt<<1],sum[rt<<1]+prelazy[rt]); lazy[rt<<1]+=lazy[rt];sum[rt<<1]+=lazy[rt]; prelazy[rt<<1|1]=max(prelazy[rt<<1|1],prelazy[rt]+lazy[rt<<1|1]); MAX[rt<<1|1]=max(MAX[rt<<1|1],sum[rt<<1|1]+prelazy[rt]); lazy[rt<<1|1]+=lazy[rt];sum[rt<<1|1]+=lazy[rt]; lazy[rt]=prelazy[rt]=0; } } void build(int l,int r,int rt){ MAX[rt]=lazy[rt]=prelazy[rt]=sum[rt]=0; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); push_up(rt); } void update(int L,int R,LL x,int l,int r,int rt){ if(L<=l&&r<=R){ sum[rt]+=x;lazy[rt]+=x; prelazy[rt]=max(prelazy[rt],lazy[rt]); MAX[rt]=max(MAX[rt],sum[rt]); return; } push_down(rt); int m=(l+r)>>1; if(L<=m) update(L,R,x,lson); if(R>m) update(L,R,x,rson); push_up(rt); } LL query(int L,int R,int l,int r,int rt){ if(L<=l && r<=R) return MAX[rt]; push_down(rt); int m=(l+r)>>1; LL res=0; if(L<=m) res=max(res,query(L,R,lson)); if(R>m) res=max(res,query(L,R,rson)); return res; } int main(){ while(~scanf("%d",&n)){ memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; } sort(q+1,q+m+1); int j=1; for(int i=1;i<=n;i++){ update(vis[a[i]+M]+1,i,a[i],1,n,1); vis[a[i]+M]=i; while(j<=m && q[j].r==i){ q[q[j].id].ans=query(q[j].l,q[j].r,1,n,1); j++; } } for(int i=1;i<=m;i++) printf("%lld\n", q[i].ans); } return 0; }