题目地址:
这题是蓝书上的题,题目大意与思路如下:
我主要说一下实现细节:
(1)维护整个序列的前缀和数组。书里没有讲到的是,维护max_prefix和max_suffix需要区间的和。因为题目要求返回的是两个区间的端点,所以我们的递归函数应该返回区间端点(因为我们不能通过和来拿到区间端点),然后通过前缀和数组,我们可以方便地访问每个区间的和。
(2)线段树里保存区间端点,而不是和
(3)防止溢出,每个数虽然在int里,但它们的和会溢出。
下面给出代码:
data[i][0]保存max_sub左端点,data[i][1]保存max_sub右端点,data[i][2]保存max_suffix右端点,data[i][3]保存max_preffix左端点。
然后使用数组保存线段树2*node+1为左节点,2*node+2为右节点。
#include <bits/stdc++.h>
using namespace std;
int dia[500005];
long long sums[500005];
int data[2000005][4];
int n;
void buildTree(int node, int l, int r)
{
//cout<<l<<" "<<r<<" "<<node<<endl;
long long tmp, tmp1, tmp2, tmp3;
int m = l +(r-l)/2;
if((l==n-1)||(r-l==1))
{
data[node][0] = l;
data[node][1] = l+1;
data[node][2] = l+1;
data[node][3] = l;
return;
}
buildTree(2*node+1,l,m);
if(m<n)
buildTree(2*node+2,m,r);
else
{
data[node][0] = data[2*node+1][0];
data[node][1] = data[2*node+1][1];
data[node][2] = data[2*node+1][2];
data[node][3] = data[2*node+1][3];
return;
}
tmp1 = sums[data[2*node+1][1]-1] - sums[data[2*node+1][0]-1];
tmp2 = sums[data[2*node+2][1]-1] - sums[data[2*node+2][0]-1];
tmp3 = sums[data[2*node+2][2]-1]-sums[data[2*node+1][3]-1];
tmp = max(max(tmp1,tmp2),tmp3);
//cout<<node<<" "<<tmp1<<tmp2<<tmp3<<endl;
if(tmp==tmp1)
{
if(tmp1==tmp3&&data[2*node+1][0]>data[2*node+1][3])
{
data[node][0] = data[2*node+1][3];
data[node][1] = data[2*node+2][2];
}
else
{
data[node][0]=data[2*node+1][0];
data[node][1]=data[2*node+1][1];
}
}
else if(tmp == tmp3)
{
data[node][0] = data[2*node+1][3];
data[node][1] = data[2*node+2][2];
}
else
{
data[node][0]=data[2*node+2][0];
data[node][1]=data[2*node+2][1];
}
if(sums[data[2*node+2][2]-1]-sums[data[2*node+1][2]-1]>0)
data[node][2] = data[2*node+2][2];
else
data[node][2] = data[2*node+1][2];
if(sums[data[2*node+2][3]-1]-sums[data[2*node+1][3]-1]>=0)
data[node][3] = data[2*node+1][3];
else
data[node][3] = data[2*node+2][3];
/*int i,j;
for(i=0;i<5;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",data[i][j]);
}
printf("\n");
}*/
}
void query(int a, int b, int l, int r, int node, int c[])
{
int i,j;
//cout<<l<<" "<<r<<" "<<a<<" "<<b<<endl;
if(b-a==1)
{
c[0]=a;
c[1]=a+1;
c[2]=a+1;
c[3]=a;
return;
}
if(a==l&&b==r)
{
c[0] = data[node][0];
c[1] = data[node][1];
c[2] = data[node][2];
c[3] = data[node][3];
return;
}
int m = l +(r-l)/2;
if(m<=a)
{
query(a,b, m, r, 2*node+2, c);
return;
}
if(m>=b)
{
query(a,b,l,m,2*node+1, c);
return;
}
int c1[4], c2[4];
long long tmp, tmp1, tmp2, tmp3;
query(a,m,l,m,2*node+1,c1);
query(m,b,m,r,2*node+2,c2);
tmp1 = sums[c1[1]-1] - sums[c1[0]-1];
tmp2 = sums[c2[1]-1] - sums[c2[0]-1];
tmp3 = sums[c2[2]-1]-sums[c1[3]-1];
tmp = max(max(tmp1,tmp2),tmp3);
//cout<<node<<" "<<tmp1<<tmp2<<tmp3<<endl;
if(tmp==tmp1)
{
if(tmp1==tmp3&&c1[0]>c1[3])
{
c[0] = c1[3];
c[1] = c2[2];
}
else
{
c[0]=c1[0];
c[1]=c1[1];
}
}
else if(tmp == tmp3)
{
c[0] = c1[3];
c[1] = c2[2];
}
else
{
c[0]=c2[0];
c[1]=c2[1];
}
if(sums[c2[2]-1]-sums[c1[2]-1]>0)
c[2] = c2[2];
else
c[2] = c1[2];
if(sums[c2[3]-1]-sums[c1[3]-1]>=0)
c[3] = c1[3];
else
c[3] = c2[3];
return;
}
int main()
{
int m, i, j, t=0;
int c[4];
while(scanf("%d%d",&n,&m)==2)
{
t++;
for(i=0;i<n;i++)
{
scanf("%d",&dia[i]);
if(i==0)
sums[0]=dia[0];
else
sums[i]=sums[i-1]+dia[i];
}
int a = log(n)/log(2), b, d = a;
//cout<<a<<endl;
buildTree(0, 0, int(pow(2,a+1)));
/*for(i=0;i<8;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",data[i][j]);
}
printf("\n");
}*/
printf("Case %d:\n",t);
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
query(a-1,b,0, int(pow(2,d+1)),0,c);
printf("%d %d\n",c[0]+1, c[1]);
}
}
}