题意:给定一个长度为 n 的序列,m 个询问 [a,b],求 [a,b] 间最大子段和的开头和结尾。

思路:用线段树解答,每个节点保存对应段的最大前缀的结尾位置,最大后缀的开头位置,最大子段的开头结尾位置。询问时将 [a,b] 间的线段数中的区间从左到右依次取出,保存为约 log2(b-a) 个子段,求这 log2(b-a) 个区间所构成的最大子段和。

由于最大子段在这些区间中只有如下三种可能性:

其中红色部分为最大子段。

显然最大子段只可能包括 1. 某个区间 A 的最大后缀、某个区间 B 的最大前缀、和这两个区间中的所有区间(可以没有)。或者 2. 某个区间的最大子段。所以可以枚举情况 2(即图中情况 2),并用 O(N)(即原题的 O(log2n))求出情况 1(即图中情况 1、3)最大子段。取两者最大值。

然而,不知为何,这个程序评测总是 WA,对拍 10000 组随机、极限、手写数据都没问题。发现错误请赶快来裱我。

#include 
#include 
#include 

#define MX 500006

using namespace std;

typedef struct nd
{
    int l,r;
    int pre,suf,jotl,jotr;
} nod;

typedef struct sege
{
    int l,r;
} seg;

nod tree[MX*4];
long long psum[MX],src[MX];
int m,n;

int input()
{
    memset(src,0,sizeof(src));
    if(!(~scanf("%d%d",&n,&m)))return 0;
    for(int i=1; i<=n; i++)scanf("%lld",&src[i]);
    return 1;
}

void init()
{
    psum[0]=0;
    for(int i=1; ipsum[b.r]-psum[b.l-1])?a:b;
    else if(a.l!=b.l)return (a.l<b.l)?a:b;
    else return a.r<b.r?a:b;
}

void build(int node,int l,int r)
{
    if(l==r)tree[node].l=l,tree[node].r=r,tree[node].jotl=l,tree[node].jotr=r,tree[node].pre=l,tree[node].suf=l;
    else
    {
        build(node*2,l,(l+r)/2);
        build(node*2+1,(l+r)/2+1,r);
        seg a,b,c,as;
        a.l=tree[node*2].jotl,a.r=tree[node*2].jotr;
        b.l=tree[node*2+1].jotl,b.r=tree[node*2+1].jotr;
        c.l=tree[node*2].suf,c.r=tree[node*2+1].pre;
        as=better(better(a,b),c);
        tree[node].jotl=as.l,tree[node].jotr=as.r;

        a.l=tree[node*2].l,a.r=tree[node*2].pre;
        b.l=tree[node*2].l,b.r=tree[node*2+1].pre;
        as=better(a,b);
        tree[node].pre=as.r;

        a.l=tree[node*2].suf,a.r=tree[node*2+1].r;
        b.l=tree[node*2+1].suf,b.r=tree[node*2+1].r;
        as=better(a,b);
        tree[node].suf=as.l;

        tree[node].l=l,tree[node].r=r;
    }
}

int ans[MX*4],anum;

long long getsum(seg a)
{
    if(a.l==0&&a.r==0)return -9999999999999999;
    return psum[a.r]-psum[a.l-1];
}

seg getblc(int i,int j)
{
    seg blc;
    if(i==j)blc.l=tree[i].jotl,blc.r=tree[i].jotr;
    else blc.l=tree[i].suf,blc.r=tree[j].pre;
    return blc;
}

int lst[MX];

seg getmax()
{
    seg now,mx1,mx2,mx3;
    mx1.l=mx2.l=mx3.l=0;
    mx1.r=mx2.r=mx3.r=0;
    for(int i=1;i<=anum;i++)lst[i]=i;
    for(int i=2;i<=anum-1;i++)
    {
        now=better(getblc(ans[i-1],ans[i+1]),getblc(ans[max(lst[i-1]-1,1)],ans[i+1]));
        mx1=better(mx1,now);
        if(getsum(now)!=getsum(getblc(ans[i-1],ans[i+1])))lst[i]=lst[i-1];
    }
    for(int i=1; i<=anum; i++)mx2=better(mx2,getblc(ans[i],ans[i]));
    for(int i=1;i<=anum-1;i++)mx3=better(mx3,getblc(ans[i],ans[i+1]));
    return better(better(mx1,mx2),mx3);
}

void query(int node,int ql,int qr)
{
    int l=tree[node].l,r=tree[node].r;
    if(ql<=l&&rr||l>qr)return;
    else
    {
        query(node*2,ql,qr);
        query(node*2+1,ql,qr);
    }
}

int main()
{
    seg tmp;
    int l,r,ks=0;
    while(input())
    {
        ks++;
        printf("Case %d:\n",ks);
        init();
        build(1,1,n);
        for(int i=1; i<=m; i++)
        {
            anum=0;
            scanf("%d%d",&l,&r);
            query(1,l,r);
            tmp=getmax();
            printf("%d %d\n",tmp.l,tmp.r);
        }
    }
    return 0;
}
分类: 文章

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注