JZOJ 4605 排序【NOIP2016模拟7.11】

排序

题目描述

这里写图片描述这里写图片描述
这里写图片描述

输入格式

这里写图片描述

输出格式

这里写图片描述

样例输入

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

样例输出

5

数据范围

这里写图片描述

题解

这一题,看上去很难,事实上还挺简单。
首先一开始想到的一定是用快速排序,但是这样子我们会求出所有位置上的数,然而我们只需求出某个位置上的数而已。

我们用二分,我们二分第 q 位置上的数。
对于每次二分,假设我们二分的数为a,将整个序列中大于等于a的值变为1,小于a的值变成0。这样序列中只有0和1。
对于每一次部分排序,我们可以通过线段树的区间更新,若为升序排序,则把该区间的0全部排在区间前段,1排在区间后段,否则反之即可。
最后全部部分排序结束后,检验位置p上的值是1还是0,来继续调整下一次二分。二分结束后,就可以知道答案了。复杂度为 O(mlog2n)

Code(Pascal)

var
    cqy:array[0..102000,1..3] of longint;
    tr:array[0..500000,0..1] of longint;
    s,la:array[0..502000] of longint;
    n,m,j,k,l,i,p,qqq,r,mid,td:longint;
procedure js(o,l,r,ccc:longint);
    var
        mid:longint;
    begin
        la[o]:=-1;
        if l=r then
        begin
             if s[l]<ccc then
            begin
                tr[o,0]:=1;
                tr[o,1]:=0;
            end
            else
            begin
                tr[o,1]:=1;
                tr[o,0]:=0;
            end;
            exit;
        end;
        mid:=(l+r) div 2;
        js(o*2,l,mid,ccc);
        js(o*2+1,mid+1,r,ccc);
        tr[o,0]:=tr[o*2,0]+tr[o*2+1,0];
        tr[o,1]:=tr[o*2,1]+tr[o*2+1,1];
    end;
function cx(o,l,r,ll,rr:longint):longint;
     var
         mid,ls,rs:longint;
     begin
         mid:=(l+r) div 2;
         ls:=o*2;
         rs:=ls+1;
        if la[o]>=0 then
        begin
            tr[ls,la[o]]:=mid-l+1;
            tr[ls,1-la[o]]:=0;
            tr[rs,la[o]]:=r-mid;
            tr[rs,1-la[o]]:=0;
            la[ls]:=la[o];
            la[rs]:=la[o];
            la[o]:=-1;
        end;
         if (l=ll) and (r=rr) then exit(tr[o,0]);
         if rr<=mid then cx:=cx(ls,l,mid,ll,rr)
         else if ll>mid then cx:=cx(rs,mid+1,r,ll,rr)
         else cx:=cx(ls,l,mid,ll,mid)+cx(rs,mid+1,r,mid+1,rr);
        tr[o,0]:=tr[ls,0]+tr[rs,0];
        tr[o,1]:=tr[ls,1]+tr[rs,1];
     end;
procedure xg(o,l,r,ll,rr,kkk:longint);
    var
        ls,mid,rs:longint;
    begin
        ls:=o*2;
        rs:=ls+1;
        mid:=(l+r) div 2;
        if (l=ll) and (r=rr) then
        begin
            la[o]:=kkk;
            tr[o,kkk]:=r-l+1;
            tr[o,1-kkk]:=0;
            exit;
        end;
        if la[o]>=0 then
        begin
            tr[ls,la[o]]:=mid-l+1;
            tr[ls,1-la[o]]:=0;
            tr[rs,la[o]]:=r-mid;
            tr[rs,1-la[o]]:=0;
            la[ls]:=la[o];
            la[rs]:=la[o];
            la[o]:=-1;
        end;
        if rr<=mid then xg(ls,l,mid,ll,rr,kkk)
        else if ll>mid then xg(rs,mid+1,r,ll,rr,kkk)
        else
        begin
            xg(ls,l,mid,ll,mid,kkk);
            xg(rs,mid+1,r,mid+1,rr,kkk);
        end;
        tr[o,0]:=tr[ls,0]+tr[rs,0];
        tr[o,1]:=tr[ls,1]+tr[rs,1];
    end;
function ok(o:longint):boolean;
    var
        i,j,k,l,p:longint;
    begin
        js(1,1,n,o);
        for i:=1 to m do
        begin
            p:=cx(1,1,n,cqy[i,2],cqy[i,3]);
            if cqy[i,1]=0 then
            begin
                if p>0 then
                xg(1,1,n,cqy[i,2],cqy[i,2]+p-1,0);
                if p<cqy[i,3]-cqy[i,2]+1 then
                xg(1,1,n,cqy[i,2]+p,cqy[i,3],1);
            end
            else
            begin
                p:=(cqy[i,3]-cqy[i,2]+1)-p;
                if p>0 then
                xg(1,1,n,cqy[i,2],cqy[i,2]+p-1,1);
                if p<cqy[i,3]-cqy[i,2]+1 then
                xg(1,1,n,cqy[i,2]+p,cqy[i,3],0);
            end;
        end;
        P:=CX(1,1,N,QQQ,QQQ);
        if p=1 then exit(false) else exit(true);
    end;
begin
    readln(n,m);
    for i:=1 to n do
    read(s[i]);
    for i:=1 to m do
    begin
        readln(cqy[i,1],cqy[i,2],cqy[i,3]);
        if cqy[i,2]>cqy[i,3] then
        begin
            td:=cqy[i,2];
            cqy[i,2]:=cqy[i,3];
            cqy[i,3]:=td;
        end;
    end;
    readln(qqq);
    l:=1;
    r:=n;
    while l+1<r do
    begin
        mid:=(l+r) div 2;
        if ok(mid) then l:=mid
        else r:=mid;
    end;
    if ok(n) then l:=n;
    writeln(l);
end.
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值