最大区间字段和

这个就是最大字段和分治算法的扩展,我于是学了一下分治求最大字段和。结果一个神奇的读入优化卡的不明不白,所以,以后决定还是少些这傻逼的读入优化,真的是错的不明不白。
我说怎么几次提交都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 或者树链剖分。。。
链接如下:小白逛公园加强版

posted @ 2017-05-06 21:21  rsqppp  阅读(206)  评论(0)    收藏  举报