bzoj 1901 线段树套平衡树+二分答案查询

我们就建一颗线段树,线段树的每一个节点都是一颗平衡树,对于每个询问来说,我们就二分答案,

查询每个二分到的mid在这个区间里的rank,然后就行了

/**************************************************************

    Problem: 1901

    User: BLADEVIL

    Language: Pascal

    Result: Accepted

    Time:3220 ms

    Memory:6592 kb

****************************************************************/

 

//By BLADEVIL

type

    rec                     =record

        left, right, root   :longint;

    end;

 

var

    n, m                    :longint;

    a                       :array[0..10010] of longint;

    t                       :array[0..40010] of rec;

    bt                      :array[0..300000] of longint;

    b_size, b_left, b_right :array[0..300000] of longint;

    b_key                   :array[0..300000] of longint;

    tot                     :longint;

     

function min(a,b:longint):longint;

begin

    if a>b then min:=b else min:=a;

end;

 

function max(a,b:longint):longint;

begin

    if a>b then max:=a else max:=b;

end;

     

procedure rotate_right(var t:longint);

var

    k                       :longint;

begin

    k:=b_left[t];

    b_left[t]:=b_right[k];

    b_right[k]:=t;

    b_size[k]:=b_size[t];

    b_size[t]:=b_size[b_right[t]]+b_size[b_left[t]]+1;

    t:=k;

end;

 

procedure rotate_left(var t:longint);

var

    k                       :longint;

begin

    k:=b_right[t];

    b_right[t]:=b_left[k];

    b_left[k]:=t;

    b_size[k]:=b_size[t];

    b_size[t]:=b_size[b_right[t]]+b_size[b_left[t]]+1;

    t:=k;

end;

     

procedure maintain(var t:longint; flag:boolean);

begin

    if not flag then

    begin

        if b_size[b_left[b_left[t]]]>b_size[b_right[t]] then

            rotate_right(b_left[t]) else

        if b_size[b_right[b_left[t]]]>b_size[b_right[t]] then

        begin

            rotate_left(b_left[t]);

            rotate_right(t);

        end else exit;

    end else

    begin

        if b_size[b_right[b_right[t]]]>b_size[b_left[t]] then

            rotate_left(b_right[t]) else

        if b_size[b_left[b_right[t]]]>b_size[b_left[t]] then

        begin

            rotate_right(b_right[t]);

            rotate_left(t);

        end else exit;

    end;

    maintain(b_left[t],false);

    maintain(b_right[t],true);

    maintain(t,true);

    maintain(t,false);

end;

     

procedure insert(var t:longint; v:longint);

begin

    if t=0 then

    begin

        inc(tot);

        t:=tot;

        b_left[t]:=0;

        b_right[t]:=0;

        b_size[t]:=1;

        b_key[t]:=v;

    end else

    begin

        inc(b_size[t]);

        if v>=b_key[t] then

            insert(b_right[t],v) else

            insert(b_left[t],v);

        maintain(t,v>=b_key[t]);

    end;

end;

     

function delete(var t:longint; v:longint):longint;

begin

    dec(b_size[t]);

    if (b_key[t]=v) 

        or (b_right[t]=0) and (v>b_key[t]) 

        or (b_left[t]=0) and (v<b_key[t]) then

    begin

        delete:=b_key[t];

        if (b_left[t]=0) or (b_right[t]=0) then

            t:=b_right[t]+b_left[t] else

                b_key[t]:=delete(b_left[t],v+1);

    end else

        if v<b_key[t] then delete:=delete(b_left[t],v) else

            delete:=delete(b_right[t],v);

end;

 

function rank(var t:longint; v:longint):longint;

begin

    if t=0 then exit(0);

    if v<=b_key[t] then rank:=rank(b_left[t],v) else

        rank:=rank(b_right[t],v)+b_size[b_left[t]]+1;

end;

     

procedure build(x,l,r:longint);

var

    mid                     :longint;

    i                       :longint;

begin

    t[x].left:=l; t[x].right:=r; 

    t[x].root:=0;

    for i:=l to r do insert(t[x].root,a[i]);

    if l=r then exit;

    mid:=(l+r) div 2;

    build(x*2,l,mid); build(x*2+1,mid+1,r);

end;

 

procedure change(x,y,z:longint);

var

    mid                     :longint;

begin

    mid:=delete(t[x].root,a[y]);

    insert(t[x].root,z);

    if t[x].left=t[x].right then exit;

    with t[x] do mid:=(left+right) div 2;

    if y>mid then change(x*2+1,y,z) else change(x*2,y,z);

end;

 

function ask(x,l,r,k:longint):longint;

var

    mid                     :longint;

begin

    ask:=0;

    if (t[x].left=l) and (t[x].right=r) then

    begin

        ask:=rank(t[x].root,k);

        exit;

    end;

    with t[x] do mid:=(left+right) div 2;

    if mid<l then ask:=ask(x*2+1,l,r,k) else

    if mid>=r then ask:=ask(x*2,l,r,k) else

    ask:=ask(x*2,l,mid,k)+ask(x*2+1,mid+1,r,k);

end;

 

function succ(var t:longint;v:longint):longint;

begin

    if t=0 then exit(-1);

    if b_key[t]<v then succ:=succ(b_right[t],v) else

    begin

        succ:=succ(b_left[t],v);

        if succ=-1 then succ:=b_key[t];

    end;

end;

 

function pred(var t:longint;v:longint):longint;

begin

    if t=0 then exit(-1);

    if b_key[t]>v then pred:=pred(b_left[t],v) else

    begin

        pred:=pred(b_right[t],v);

        if pred=-1 then pred:=b_key[t]; 

    end;

end;

 

function ask_succ(x,l,r,y:longint):longint;

var

    mid                     :longint;

begin

    if (t[x].left=l) and (t[x].right=r) then

    begin

        ask_succ:=succ(t[x].root,y);

        if ask_succ=-1 then ask_succ:=maxlongint;

        exit;

    end;

    with t[x] do mid:=(left+right) div 2;

    if l>mid then ask_succ:=ask_succ(x*2+1,l,r,y) else

    if r<=mid then ask_succ:=ask_succ(x*2,l,r,y) else

    ask_succ:=min(ask_succ(x*2,l,mid,y),ask_succ(x*2+1,mid+1,r,y));

end;

 

function ask_pred(x,l,r,y:longint):longint;

var

    mid                     :longint;

begin

    if (t[x].left=l) and (t[x].right=r) then

    begin

        ask_pred:=pred(t[x].root,y);

        exit;

    end;

    with t[x] do mid:=(left+right) div 2;

    if l>mid then ask_pred:=ask_pred(x*2+1,l,r,y) else

    if r<=mid then ask_pred:=ask_pred(x*2,l,r,y) else

    ask_pred:=max(ask_pred(x*2,l,mid,y),ask_pred(x*2+1,mid+1,r,y));

end;

 

procedure query(x,y,k:longint);

var

    l, r, mid               :longint;

    ans                     :longint;

    xx                      :longint;

begin

    l:=1; r:=1000000000;

    while l<=r do

    begin

        mid:=(l+r) div 2;

        xx:=ask(1,x,y,mid);

        if xx>=k-1 then

        begin

            ans:=mid;

            r:=mid-1;

        end else l:=mid+1;

    end;

    if ask(1,x,y,ans)<>k-1 then

        xx:=ask_pred(1,x,y,ans-1) else

        xx:=ask_succ(1,x,y,ans);

    writeln(xx);

end;

 

procedure init;

var

    i                       :longint;

begin

    read(n,m);

    for i:=1 to n do read(a[i]);

    readln;

    build(1,1,n);

end;

 

procedure main;

var

    i                       :longint;

    ch                      :char;

    l, r, x                 :longint;

     

begin

    for i:=1 to m do

    begin

        read(ch);

        if ch='Q' then

        begin

            readln(l,r,x);

            query(l,r,x);

        end else

        begin

            readln(l,x);

            change(1,l,x);

            a[l]:=x;

        end;

    end;

end;

 

begin

    init;

    main;

end.

 

你可能感兴趣的:(线段树)