http://poj.org/problem?id=2750

最近在poj上做的线段树题 c++提交要比g++提交快很多,

我知道c++要快一些,不过快的有点离谱了吧,都左右是否超时了

题目大意:

n盆花围成圈 每盆花都有它的value

要做一个弧形长椅 不能是一个圆,因为必须有缺口,使得长椅附近花的value值和最大

m次替换 每替换一次问替换后的最佳答案

本题的难点在于环,因为线段树的建立是线状的

所以在求最终答案是要注意

线段树要保存本段从左起最大值,最小值,从右起最大值,最小值,和总体最大值,最小值,总和

最大值和最小值都必须至少包含一盆花

这都是为求最后答案做准备。

最后答案基本分两种

1.最小值为正,此时用最大减最小就可以了(因为必须有缺口)

2.最小值为负,有可能是根的最大值,但也要考虑它是环的特性(判定缺口的位置),具体见代码注释。

代码及其注释:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
const int N=100005;
struct node
{
    int l,r;
    int highest,lhighest,rhighest;
    int lowest ,llowest, rlowest;
    int sum;
}mem[N*3];
int value[N];
int MAX(int a,int b,int c)
{
    if(b>a)a=b;
    if(c>a)a=c;
    return a;
}
int MIN(int a,int b,int c)
{
    if(b<a)a=b;
    if(c<a)a=c;
    return a;
}
int MAX(int a,int b,int c,int d)
{
    if(b>a)a=b;
    if(c>a)a=c;
    if(d>a)a=d;
    return a;
}
void build(int x,int l,int r)
{
    mem[x].l=l;
    mem[x].r=r;
    if(l==r)//叶子结点 值的确定
    {
        mem[x].highest=value[l];
        mem[x].lhighest=value[l];
        mem[x].rhighest=value[l];
        mem[x].lowest=value[l];
        mem[x].llowest=value[l];
        mem[x].rlowest=value[l];
        mem[x].sum=value[l];
    }
    else
    {
        int mid=(l+r)>>1;
        build(x*2,l,mid);
        build(x*2+1,mid+1,r);
        mem[x].sum=mem[x*2].sum+mem[x*2+1].sum;//各种合并,要注意的是不能产生不连接状况
        mem[x].lhighest=max(mem[x*2].lhighest,mem[x*2].sum+mem[x*2+1].lhighest);
        mem[x].rhighest=max(mem[x*2+1].rhighest,mem[x*2+1].sum+mem[x*2].rhighest);
        mem[x].highest=MAX(mem[x].lhighest,mem[x].rhighest,mem[x*2].rhighest+mem[x*2+1].lhighest);
        mem[x].llowest=min(mem[x*2].llowest,mem[x*2].sum+mem[x*2+1].llowest);
        mem[x].rlowest=min(mem[x*2+1].rlowest,mem[x*2+1].sum+mem[x*2].rlowest);
        mem[x].lowest=MIN(mem[x*2].lowest,mem[x*2+1].lowest,mem[x*2].rlowest+mem[x*2+1].llowest);
    }

}
void findmin(int x,int i,int b)
{
    if(mem[x].l==mem[x].r)//修改叶子结点值
    {
        mem[x].lowest=b;
        mem[x].llowest=b;
        mem[x].rlowest=b;
        mem[x].highest=b;
        mem[x].lhighest=b;
        mem[x].rhighest=b;
        mem[x].sum=b;
    }
    else
    {
        int mid=(mem[x].l+mem[x].r)>>1;
        if(i<=mid)//判定往哪搜
        findmin(x*2,i,b);
        else
        findmin(x*2+1,i,b);
        mem[x].sum=mem[x*2].sum+mem[x*2+1].sum;//各种合并,要注意的是不能产生不连接状况
        mem[x].lhighest=max(mem[x*2].lhighest,mem[x*2].sum+mem[x*2+1].lhighest);
        mem[x].rhighest=max(mem[x*2+1].rhighest,mem[x*2+1].sum+mem[x*2].rhighest);
        mem[x].highest=MAX(mem[x].lhighest,mem[x].rhighest,mem[x*2].rhighest+mem[x*2+1].lhighest);
        mem[x].llowest=min(mem[x*2].llowest,mem[x*2].sum+mem[x*2+1].llowest);
        mem[x].rlowest=min(mem[x*2+1].rlowest,mem[x*2+1].sum+mem[x*2].rlowest);
        mem[x].lowest=MIN(mem[x*2].lowest,mem[x*2+1].lowest,mem[x*2].rlowest+mem[x*2+1].llowest);
    }
}
int main()
{
    //freopen("data.txt","r",stdin);
    int n;
    scanf("%d",&n);
    int M=0;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&value[i]);
            M=value[i];
        }
        build(1,1,n);
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int i,b;
            scanf("%d %d",&i,&b);
            findmin(1,i,b);
            int ans;
            if(mem[1].lowest>0)
            {
                ans=mem[1].highest-mem[1].lowest;
            }
            else
            {//考虑到他是环的状况所以 这里要仔细呀 可能是根结点最大,对于环
                //1.缺口是线段了两头。2.缺口在左半。3.缺口在右半
                ans=MAX(mem[1].highest,mem[2].lhighest+mem[3].rhighest,mem[2].sum-mem[2].lowest+mem[3].sum,
                        mem[3].sum-mem[3].lowest+mem[2].sum);
            }
            printf("%d\n",ans);

        }
    return 0;
}

  

posted on 2012-06-13 18:15  夜->  阅读(201)  评论(0编辑  收藏  举报