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;
}
浙公网安备 33010602011771号