bzoj 2120 线段树套平衡树

先吐下槽,改了快一个小时,最后发现是SBT的delete写错了,顿时就有想死的心。。。。。

首先对于这道题,我们应该先做一下他的小问题,bzoj1878,虽然和这道题几乎一点关系没有,

但是能给我们一个思路的启发

我们先考虑没有修改,只有区间询问

内个我下面的糖果是画笔的意思。。。我也不知道咋着题就读错了。。。。

那么对于一个糖果i,假设他的颜色是col,那么我们找到col颜色上一次出现的位置,为color[i],

那么对于一个区间L R里的color值,我们要找不同的颜色,那么假设一种颜色在L R里出现多次

那么这些糖果的color值除了最先出现的以外,剩下的color值都大于等于L,也就是我们要找在区间

L R里的color值比L小的个数就行了。我们可以用线段树套平衡树来比较容易的实现这一过程

//时间复杂度是O(nlog^2(n))的,1878做不了

树套树就相当于维护color数组用的

那么我们在修改一个位置的颜色的时候,假设把位置I的颜色改为y,原来的颜色为x

那么我们需要修改的是

i位置后面第一个颜色为X的color值改为i的color值

I位置的color值改为i前面最后一个颜色为Y的位置

I位置后面第一个颜色为Y的color值改为I

这样就行了,那么我们为了快速找到“I位置后面第一个颜色为X的糖果的位置”,需要对于每种颜色

建一颗平衡树,关键字为位置,只需要找到后继就行了

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

    Problem: 2120

    User: BLADEVIL

    Language: Pascal

    Result: Accepted

    Time:2024 ms

    Memory:16280 kb

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

 

//By BLADEVIL

type

    rec                     =record

        left, right, root   :longint;

    end;

 

var

    n, m                    :longint;

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

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

    c_pred, c_root          :array[0..1000010] of longint;

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

    tot                     :longint;

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

    b_size, b_key           :array[0..500000] of longint;

 

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_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_left[t],v) else insert(b_right[t],v);

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

    end;

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,color[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;

 

procedure init;

var

    i                       :longint;

begin

    read(n,m);

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

    for i:=1 to n do

    begin

        color[i]:=c_pred[a[i]];

        c_pred[a[i]]:=i;

    end;

    for i:=1 to n do c_root[a[i]]:=0;

    for i:=1 to n do

        insert(c_root[a[i]],i);

    build(1,1,n);

end;

 

function select(t,v:longint):longint;

begin

    if t=0 then exit(0);

    if b_key[t]>=v then

        select:=select(b_left[t],v) else

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

end;

 

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

var

    mid                     :longint;

begin

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

    begin

        query:=select(t[x].root,y);

        exit;

    end;

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

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

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

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

end;

 

procedure ask(l,r:longint);

begin

    writeln(query(1,l,r,l));

end;

 

function 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

        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]:=delete(b_left[t],v+1);

    end else

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

end;

 

procedure t_change(x,y,z,xx:longint);

var

    mid                     :longint;

begin

    delete(t[x].root,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 xx>mid then t_change(2*x+1,y,z,xx) else

        t_change(2*x,y,z,xx);

end;

 

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

begin

    if t=0 then exit(0);

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

    begin

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

        if pred=0 then pred:=b_key[t];

    end;

end;

 

function succ(t,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;

 

procedure change(x,y:longint);

var

    w1, w2, w3              :longint;

     

begin

    if a[x]=y then exit;

    w1:=a[x];

    w2:=pred(c_root[w1],x);

    w3:=succ(c_root[w1],x);

    if w3<>-1 then t_change(1,x,w2,w3);

    delete(c_root[w1],x);

    w1:=w2;

    w3:=succ(c_root[y],x);

    w2:=pred(c_root[y],x);

    if w3<>-1 then t_change(1,w2,x,w3);

    t_change(1,w1,w2,x);

    a[x]:=y;

    insert(c_root[y],x);

end;

 

procedure main;

var

    i                       :longint;

    ch                      :char;

    x, y                    :longint;

begin

    readln;

    for i:=1 to m do

    begin

        read(ch);

        readln(x,y);

        if ch='Q' then

            ask(x,y) else

            change(x,y);

    end;

     

end;

 

begin

    init;

    main;

end.

 

 

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