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; }