1. 程式人生 > >GSS2 Can you answer these queries II(線段樹)

GSS2 Can you answer these queries II(線段樹)

題目大意:給你一個長度為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;
}