最大区间字段和
这个就是最大字段和分治算法的扩展,我于是学了一下分治求最大字段和。结果一个神奇的读入优化卡的不明不白,所以,以后决定还是少些这傻逼的读入优化,真的是错的不明不白。
我说怎么几次提交都wa了
修正后的读入优化
int gi(){
int x = 0;char c = 0;int flag = 1;
while(c<'0'||c > '9'){if(c =='-') flag = -1;c = getchar();}
while(c>='0'&&c<='9'){x = x*10+c-'0';c = getchar();}
return x*flag;
}
核心算法,
int query(int L,int R)
{
if(L == R) return A[L];
int M = (R+L)/2;
int ans = max(query(L,M),query(M+1,R));
int Lmax = -INF,Rmax = -INF;
for(int i = M;i >= L;i--) Lmax = max(Lmax,S[M]-S[i-1]);
for(int i = M+1;i <= R;i++) Rmax = max(Rmax,S[i] - S[M]);
ans = max(ans,Lmax+Rmax);
return ans;
}
实现区间查询就是把这个分治算法转化成线段树。
调试了很久发现其实是区间覆盖出错了。
常规的这样的,
因为大区间可以得到子区间的答案,然而这里,显然不是。
if(L <= q1&& q2 <= R) return tree[o];
所以,换一种构造答案的方法,
Node operator+(const Node&l,const Node&r)
{
Node f;
f.L=max(l.L,l.S+r.L);
f.R=max(r.R,r.S+l.R);
f.S=l.S+r.S;
f.M=max(l.M,r.M);
f.M=max(f.M,l.R+r.L);
return f;
}
然后查询结束为:
if(a <= L&&R <= b) return tree[o];
L 为左起最大字段和,R为右起最大字段,M为区间最大字段,S为段和。
这样构造是怎么呢,加入最长字段完全覆盖左边,则为左边,完全覆盖右边,则为右边字段最大和,负责取左边右字段和右边左字段和,更新答案,
这样,当查询区间完全覆盖当前区间是,直接返回当前区间。
当然,这个题还有一个加强版,需要link-cut tree 或者树链剖分。。。
链接如下:小白逛公园加强版

浙公网安备 33010602011771号