JZOJ4663 Seq 莫队5题2/5

8 篇文章 0 订阅

Description
这里写图片描述
1≤n,m≤50000
题解:
最简单的想法就是用莫队处理,然后加上线段树维护区间最大子段和,可是这样的时间复杂度是O(Nsqrt(n)logn),会达到10^8,这就非常不和谐了,那么我们怎么办呢?
对于维护区间最大子段和,我们可以考虑假如所有的操作都是插入操作,那么答案一定是不下降的,所以此时直接维护莫队的两个端点lr就可以了,问题是还有删除操作,那么又该怎么办呢?
我们可以把删除操作看作是还原插入操作,可是还是要打删除操作,但是我们可以转换一下处理方式。
每一次从b[i].l(r)扩展到b[i+1].l(r)(假设b[i].l>b[i+1].l)那么,我们可以把扩展前的值存储下来,然后扩展,扩展完后在暴力恢复,这样就可以保证不会出现删除操作了。
对于维护区间最大子段和,可以维护这个子段和的左右和中间端点,然后进行计算就可以了,细节比较多。
代码(长又丑)

uses math;
type node=record
        l,r,id,bl:longint;
end;
var
        i,j,n,m,size,now,l,r,cnt:longint;
        a,ans,lp,rp:array[0..100000]of longint;
        did:array[0..100000,0..3]of longint;
        b:array[-1..100000]of node;
        bo:array[0..100000]of boolean;
procedure qsort(l,r:longint);
var
        i,j,m,m1:longint;
begin
        i:=l;
        j:=r;
        m:=b[(l+r)div 2].bl;
        m1:=b[(l+r)div 2].r;
        repeat
                while (b[i].bl<m)or((b[i].bl=m)and(b[i].r<m1))do inc(i);
                 while (b[j].bl>m)or((b[j].bl=m)and(b[j].r>m1))do dec(j);
                 if i<=j then
                 begin
                        b[-1]:=b[i];
                        b[i]:=b[j];
                        b[j]:=b[-1];
                        inc(i);
                        dec(j);
                 end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
end;
procedure recover(u:longint);
var
        i,j:longint;
        x,y,z:longint;
begin
        x:=did[u][2];
        y:=did[u][0];
        z:=did[u][1];
        bo[x]:=false;
        if (y<x)then
        begin
                rp[y]:=x-1;
                lp[x-1]:=y;
        end;
        if (x<z)then
        begin
                rp[x+1]:=z;
                lp[z]:=x+1;
        end;
end;
procedure change(x,pd:longint);
var
        delta,y:longint;
begin
         if (l<=r)then
         begin
                delta:=0;
                x:=a[x];
                bo[x]:=true;
                lp[x]:=x;
                rp[x]:=x;
                if (pd<>0)then
                begin
                        inc(cnt);
                        did[cnt,0]:=x;
                        did[cnt,1]:=x;
                        did[cnt,2]:=x;
                end;
                if (x<>0)and(bo[x-1])then
                begin
                        delta:=delta+x-lp[x-1];
                        lp[x]:=lp[x-1];
                        rp[lp[x-1]]:=x;
                        if pd=1 then
                        did[cnt,0]:=lp[x-1]
                        else did[cnt,0]:=0;
                end;
                if (x+1<=n)and(bo[x+1])then
                begin
                        y:=lp[x];
                        delta:=delta+rp[x+1]-x;
                        rp[y]:=rp[x+1];
                        lp[rp[x+1]]:=y;
                        if pd=1 then
                        did[cnt][1]:=rp[x+1]
                        else did[cnt,1]:=0;
                end;
                now:=max(now,delta+1);
         end;
end;
procedure solve;
var
        i,j,k:longint;
        tmp,tail:longint;
begin
        for i:=1 to m do
        begin
                if (i=1)or(b[i].bl<>b[i-1].bl)then
                begin
                        fillchar(bo,sizeof(bo),false);
                        tail:=min(b[i].bl*size,n)+1;
                        now:=0;
                        l:=tail;r:=0;
                end;
                while (r<b[i].r)do
                begin
                        inc(r);
                        change(r,0);
                end;
                cnt:=0;
                tmp:=now;
                while (l>b[i].l)do
                begin
                        dec(l);
                        change(l,1);
                end;
                ans[b[i].id]:=now;
                now:=tmp;
                l:=tail;
                while cnt<>0 do
                begin
                        recover(cnt);
                        dec(cnt);
                end;
        end;
end;
begin
        readln(n,m);
        for i:=1 to n do read(a[i]);
        size:=trunc(sqrt(n))+1;
        for i:=1 to m do
        begin
                read(b[i].l,b[i].r);
                b[i].id:=i;
                b[i].bl:=(b[i].l-1)div size+1;
        end;
        qsort(1,m);
        solve;
        for i:=1 to m do
        begin
                writeln(ans[i]);
        end;
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值