bzoj 2141 线段树套平衡树

用树套树来解决这个问题,存储每个节点的数值是多少,然后交换

对于答案的变更可以讨论下,假设交换的是x,y位置的数x<=y

如果x=y || high[x]=high[y]则对答案没有影响

如果high[x]<high[y],那么首先交换x,y会对这两个点的逆序对数增加1,否则减小1

那么这是对于这两个数中间的数的逆序对的影响就是:

x的移动会令在这个区间里比x权值小的数与x不在为逆序对,所以答案减少个数

同时令比x的权值大的数多一个与x的逆序对,所以答案增加个数。

y类似,在此不再赘述

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

    Problem: 2141

    User: BLADEVIL

    Language: Pascal

    Result: Accepted

    Time:3408 ms

    Memory:79600 kb

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

 

//By BLADEVIL

type

    rec                     =record

        left, right, root   :longint;

    end;

     

var

    n, m                    :longint;

    high                    :array[0..20010] of longint;

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

    b_left, b_right, b_key  :array[0..5000010] of longint;

    b_size                  :array[0..5000010] of longint;

    tot                     :longint;

    ans                     :longint;

     

procedure swap(var a,b:longint);

var

    c                       :longint;

begin

    c:=a; a:=b; b:=c;

end;

     

procedure left_rotate(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_left[t]]+b_size[b_right[t]]+1;

    t:=k;

end;    

 

procedure right_rotate(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_left[t]]+b_size[b_right[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

            right_rotate(t) else

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

        begin

            left_rotate(b_left[t]);

            right_rotate(t);

        end else exit;  

    end else

    begin

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

            left_rotate(t) else

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

        begin

            right_rotate(b_right[t]);

            left_rotate(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_size[t]:=1;

        b_left[t]:=0;

        b_right[t]:=0;

        b_key[t]:=v;

    end else

    begin

        inc(b_size[t]);

        if v<b_key[t] then insert(b_left[t],v) else insert(b_right[t],v);

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

    end;

end;

 

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

begin

    dec(b_size[t]);

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

    begin

        b_delete:=b_key[t];

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

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

    end else

        if v>=b_key[t] then exit(b_delete(b_right[t],v)) else exit(b_delete(b_left[t],v));

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,high[i]);

    if l=r then exit;

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

    build(2*x,l,mid);

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

end;

 

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

begin

    if t=0 then exit(0);

    if b_key[t]>=v then exit(b_less(b_left[t],v)) else

        exit(b_size[b_left[t]]+1+b_less(b_right[t],v));

end;

 

function less(x,l,r,v:longint):longint;

var

    mid                     :longint;

begin

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

        exit(b_less(t[x].root,v));

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

    if mid<l then exit(less(2*x+1,l,r,v)) else

    if mid>=r then exit(less(2*x,l,r,v)) else

        exit(less(2*x,l,mid,v)+less(2*x+1,mid+1,r,v));

end;

 

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

begin

    if t=0 then exit(0);

    if b_key[t]<=v then exit(b_greater(b_right[t],v)) else

        exit(b_size[b_right[t]]+1+b_greater(b_left[t],v));

end;

 

function greater(x,l,r,v:longint):longint;

var

    mid                     :longint;

begin

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

        exit(b_greater(t[x].root,v));

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

    if mid<l then exit(greater(2*x+1,l,r,v)) else

    if mid>=r then exit(greater(2*x,l,r,v)) else

        exit(greater(2*x,l,mid,v)+greater(2*x+1,mid+1,r,v));

end;

 

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

var

    mid                     :longint;

begin

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

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

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

    if mid<y then change(2*x+1,y,v) else change(2*x,y,v);

end;

 

procedure delete(x,y,v:longint);

var

    mid                     :longint;

begin

    b_delete(t[x].root,v);

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

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

    if mid<y then delete(2*x+1,y,v) else delete(2*x,y,v);

end;

 

procedure init;

var

    i                       :longint;

begin

    read(n);

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

    build(1,1,n); 

end;

 

procedure main;

var

    i                       :longint;

    x, y                    :longint;

     

begin  

    read(m);

    for i:=1 to n-1 do

        ans:=ans+less(1,i+1,n,high[i]);

    writeln(ans);

    for i:=1 to m do

    begin

        read(x,y);

        if (x=y) or (high[x]=high[y]) then

        begin

            writeln(ans);

            continue;

        end;

        if x>y then swap(x,y);

        if high[x]<high[y] then inc(ans) else dec(ans); 

        if x+1<>y then

        begin

            ans:=ans-less(1,x+1,y-1,high[x]);

            ans:=ans+greater(1,x+1,y-1,high[x]);

            ans:=ans+less(1,x+1,y-1,high[y]);

            ans:=ans-greater(1,x+1,y-1,high[y]);

        end;

        delete(1,x,high[x]);

        change(1,x,high[y]);

        delete(1,y,high[y]);

        change(1,y,high[x]);

        swap(high[x],high[y]);

        writeln(ans);

    end;

end;

 

begin

    init;

    main;

end.

 

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