SPOJ 1557(线段树)

题意大概是说给定一个区间,求最大连续和

完全不会,学习了半天

大概可以理解为一个线段树点更新,区间询问的题目,但是构造和理解起来相对难许多。

 

这里相同数的处理还是蛮有意思。用pre[i]记录i上一次出现的位置。所以update的时候跳过这个位置就好

用离线算法,将询问区间按r排序后,从第一个至最后一个数依次加入线段树,同时维护四个值:

1.sum 目前区间和

2.maxo 最大区间和

3.lazy 待下传的和

4.lazyo 待下传的最大可更新值

 

最关键的是pushdown函数

sum、lazy和普通的更新没什么区别,重点在于maxo和lazyo

可以注意到,当lazy<=0时,lazyo是一直为0的。因为如果加入的连续和<=0,maxo不可能被更新

lazy和lazyo不可分别写一个if,因为lazy将更新sum,而sum的更新可能会改变maxo

具体看代码

#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"vector"
#define ll long long
#define mems(a,b) memset(a,b,sizeof(a))
#define ls pos<<1
#define rs pos<<1|1

using namespace std;
const int MAXN = 100500;
const int MAXE = 200500;
const int INF = 0x3f3f3f;

struct node{
    int l,r;
    ll sum,maxo,lazyo,lazy;
}node[MAXN<<2];

struct nod{
    int a,b,id;
}que[MAXN];

int pre[MAXN*2+10];
ll ans[MAXN],x[MAXN];

bool cmp(nod x,nod y){
    return x.b<y.b;
}

void build(int l,int r,int pos){
    node[pos].l=l;
    node[pos].r=r;
    node[pos].lazy=node[pos].lazyo=0;
    node[pos].sum=node[pos].maxo=0;
    if(l==r) return;
    int mid=(l+r)>>1;;
    build(l,mid,pos<<1);
    build(mid+1,r,pos<<1|1);
}

void pushup(int pos){
    node[pos].sum=max(node[ls].sum,node[rs].sum);
    node[pos].maxo=max(node[ls].maxo,node[rs].maxo);
}

void pushdown(int pos){
    if(node[pos].lazy||node[pos].lazyo){
        node[ls].lazyo=max(node[ls].lazyo,node[ls].lazy+node[pos].lazyo);
        node[ls].maxo=max(node[ls].maxo,node[ls].sum+node[pos].lazyo);
        node[ls].lazy+=node[pos].lazy;
        node[ls].sum+=node[pos].lazy;

        node[rs].lazyo=max(node[rs].lazyo,node[rs].lazy+node[pos].lazyo);
        node[rs].maxo=max(node[rs].maxo,node[rs].sum+node[pos].lazyo);
        node[rs].lazy+=node[pos].lazy;
        node[rs].sum+=node[pos].lazy;

        node[pos].lazy=node[pos].lazyo=0;
    }
}

void update(int l,int r,int pos,int add){
    if(l<=node[pos].l&&node[pos].r<=r){
        node[pos].sum+=add;
        node[pos].lazy+=add;
        node[pos].lazyo=max(node[pos].lazyo,node[pos].lazy);
        node[pos].maxo=max(node[pos].sum,node[pos].maxo);
        return;
    }
    pushdown(pos);
    int mid=(node[pos].l+node[pos].r)>>1;
    if(l<=mid) update(l,r,ls,add);
    if(r>mid) update(l,r,rs,add);
    pushup(pos);
}

ll query(int l,int r,int pos){
    if(l<=node[pos].l&&node[pos].r<=r){
        return node[pos].maxo;
    }
    ll t=0;
    pushdown(pos);
    int mid=(node[pos].l+node[pos].r)>>1;
    if(l<=mid) t=max(t,query(l,r,ls));
    if(r>mid) t=max(t,query(l,r,rs));
    return t;
}

int main(){
    int n,q;
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++) scanf("%lld",&x[i]);
        build(1,n,1);
        scanf("%d",&q);
        for(int i=0;i<q;i++){
            scanf("%d%d",&que[i].a,&que[i].b);
            que[i].id=i;
        }
        sort(que,que+q,cmp);
        mems(pre,0);
        int j=0;
        for(int i=1;i<=n;i++){
            update(pre[MAXN+x[i]]+1,i,1,x[i]);
            pre[MAXN+x[i]]=i;
            while(j<q&&que[j].b==i){
                ans[que[j].id]=query(que[j].a,que[j].b,1);
                j++;
            }
        }
        for(int i=0;i<q;i++) printf("%lld\n",ans[i]);
    }
    return 0;
}
View Code

 

posted @ 2016-01-11 19:17  Septher  阅读(289)  评论(0编辑  收藏  举报