想了许久,最终决定写下这篇博文,这是我这周做的一道很不错的题目,线段树好神奇啊!,前一段时间复习了一下线段,找了找刘汝佳蓝书上线段树的专题做了做。这题让我卡了一天,自己先用了类似的方法,但是到询问的地方感觉怎么都写不对。后来我参考了一下网上的代码,终于搞懂刘所用到的解法了。
要做这一题,我们要先定义一个结构体
struct node{
pair<int,int>max_sub;//记录最大连续段的起点位置和终点位置
int max_perfix;//记录最大前缀和的终点位置
int max_suffix;//记录最大后缀和的起点位置
}
还需要搞懂一些数学知识
比如要找一个区间内连续最大和,有三种可能性
1连续最大和都在左子树区间内
2连续最大和都在右子树区间内
3连续最大和在整个区间内(左子树的最大后缀+右子树的最大前缀)
还有一点就是建树的时候前缀结束的位置和后缀开始的位置能提前尽量提前
接下来询问是重点
询问区间的时候
1如果当前区间是询问区间的子区间的话,则它的最大连续和则是它的解
2如果当前区间是有不完全的包含关系的话,则要比较左子树最大区间和,右子树最大区间和和区间x的最大区间和(x为[[qL,R1]中的最大后缀和,[L2,qR]中的最大前缀和])
最后提一下算[qL,R1]中的最大后缀和,[L2,qR]中的最大前缀和
1就是将[qL,R1]继续拆分,拆分为两个子区间,比较[qL,R3]中的最大后缀和+[L4,R4](R4==R1)和[L4,R4]中的最大后缀和
2就是将[L2,qR]继续拆分,拆分为两个子区间,比较[L6,qR]中的最大前缀和+[L5,R5](L5==L2)和[L5,R5]中的最大前缀和
这题也可以算是一道比较复杂的递归题
#include<cstdio>
#include<utility>
#define N 500005
using namespace std;
typedef long long LL;
LL m_sum[N];
int qL,qR;
struct node{
int max_perfix;
int max_suffix;
pair<int, int>max_sub;
}node[4*N];
LL cacl_sum(int L,int R){
return m_sum[R]-m_sum[L-1];
}
pair<int, int> better(pair<int, int>a,pair<int , int>b){
if(cacl_sum(a.first, a.second)>cacl_sum(b.first, b.second))
return a;
else if(cacl_sum(a.first, a.second)<cacl_sum(b.first, b.second))
return b;
else if(a<b)
return a;
else
return b;
}
void build(int o,int L,int R){
if(L==R){
node[o].max_perfix=node[o].max_suffix=L;
node[o].max_sub=make_pair(L, L);
return;
}
int mid=(L+R)/2;
build(o*2, L, mid);
build(o*2+1, mid+1, R);
LL x1,x2;
x1=cacl_sum(L, node[o*2].max_perfix);
x2=cacl_sum(L, node[o*2+1].max_perfix);
if(x1==x2)node[o].max_perfix=node[o*2].max_perfix;
else if(x1>x2) node[o].max_perfix=node[o*2].max_perfix;
else node[o].max_perfix=node[o*2+1].max_perfix;
x1=cacl_sum(node[o*2].max_suffix,R);
x2=cacl_sum(node[o*2+1].max_suffix,R);
if(x1==x2)node[o].max_suffix=node[o*2].max_suffix;
else if(x1>x2) node[o].max_suffix=node[o*2].max_suffix;
else node[o].max_suffix=node[o*2+1].max_suffix;
node[o].max_sub=better(node[o*2].max_sub, node[o*2+1].max_sub);
node[o].max_sub=better(node[o].max_sub, make_pair(node[o*2].max_suffix, node[o*2+1].max_perfix));
}
pair<int, int>query_perfix(int o,int L,int R){
if(qR>=node[o].max_perfix)return make_pair(L, node[o].max_perfix);
int mid=(L+R)/2;
if(qR<=mid)return query_perfix(o*2, L, mid);
pair<int, int>x;
x=query_perfix(o*2+1, mid+1, R);
x.first=L;
return better(make_pair(L,node[o*2].max_perfix), x);
}
pair<int, int>query_suffix(int o,int L,int R){
if(qL<=node[o].max_suffix)return make_pair(node[o].max_suffix,R);
int mid=(L+R)/2;
if(qL>mid)return query_suffix(o*2+1, mid+1,R);
pair<int, int>x;
x=query_suffix(o*2, L, mid);
x.second=R;
return better(make_pair(node[o*2+1].max_suffix,R), x);
}
pair<int, int>query(int o,int L,int R){
if(qL<=L&&qR>=R)
return node[o].max_sub;
int mid=(L+R)/2;
if(qR<=mid) return query(o*2, L, mid);
if(qL>mid) return query(o*2+1, mid+1, R);
pair<int, int>x1,x2,x3;
x1=query_suffix(o*2,L,mid);
x2=query_perfix(o*2+1,mid+1,R);
x3=better(query(o*2, L, mid), query(o*2+1,mid+1,R));
return better(make_pair(x1.first, x2.second), x3);
}
int main(){
int n,m,x,m_count=0;
while (scanf("%d%d",&n,&m)!=EOF) {
for(int i=1;i<=n;i++){
scanf("%d",&x);
m_sum[i]=m_sum[i-1]+x;
}
build(1, 1, n);
printf("Case %d:\n",++m_count);
while(m--){
scanf("%d%d",&qL,&qR);
pair<int, int>ans=query(1, 1, n);
printf("%d %d\n",ans.first,ans.second);
}
}
return 0;
}
博主分享做线段树题目求区间连续最大和的解题过程。先复习线段树专题,起初解题遇困难,参考网上代码后搞懂解法。介绍定义结构体、找区间连续最大和的三种可能情况,重点阐述询问区间的方法及计算最大后缀和、最大前缀和的拆分比较方式。

1172

被折叠的 条评论
为什么被折叠?



