bzoj 1878 SDOI2009树状数组 离线操作

本来想写2120的,结果想起来了这个

我们先对于询问左端点排序,用树状数组存区间字母个数,对于每种字母,

第一次出现的位置记录为1,剩下的记录为0,然后记录下,每种颜色

后面第一个和他相同颜色的位置

然后扫询问,对于一个询问直接输出区间和,然后假设当前询问是

l1,r1,下一询问是,l2,r2,我们把l1到l2区间内的每个位置颜色的后一颜色

赋值成1,然后继续处理下个询问就好了。

 

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

    Problem: 1878

    User: BLADEVIL

    Language: Pascal

    Result: Accepted

    Time:3260 ms

    Memory:29524 kb

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

 

//By BLADEVIL

var

    n, m                :longint;

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

    l, r                :array[0..200010] of longint;

    other               :array[0..50010] of longint;

    last, first         :array[0..1000010] of longint;

    num, ans            :array[0..1000010] of longint;

    c                   :array[0..3000010] of longint;

    tot                 :longint;

     

procedure swap(var a,b:longint);

var

    c                   :longint;

begin

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

end;

     

procedure qs(low,high:longint);

var

    i, j, x             :longint;

begin

    i:=low; j:=high; x:=l[(i+j) div 2];

    while i<j do

    begin

        while l[i]<x do inc(i);

        while l[j]>x do dec(j);

        if i<=j then

        begin

            swap(l[i],l[j]); swap(r[i],r[j]);

            swap(num[i],num[j]);

            inc(i); dec(j);

        end;

    end;

    if i<high then qs(i,high);

    if j>low then qs(low,j);

end;

 

procedure qs1(low,high:longint);

var

    i, j, x             :longint;

begin

    i:=low; j:=high; x:=num[(i+j) div 2];

    while i<j do

    begin

        while num[i]<x do inc(i);

        while num[j]>x do dec(j);

        if i<=j then

        begin

            swap(l[i],l[j]); swap(r[i],r[j]);

            swap(num[i],num[j]); swap(ans[i],ans[j]);

            inc(i); dec(j);

        end;

    end;

    if i<high then qs1(i,high);

    if j>low then qs1(low,j);

end;

 

 

procedure init;

var

    i                   :longint;

begin

    read(n);

    for i:=1 to n do

    begin

        read(a[i]);

        if tot<a[i] then tot:=a[i];

    end;

     

    read(m);

    for i:=1 to m do read(l[i],r[i]);

    for i:=1 to m do num[i]:=i;

    qs(1,m);

    for i:=1 to n do

        if last[a[i]]<>0 then

        begin

            other[last[a[i]]]:=i;

            last[a[i]]:=i;

        end else

        begin

            last[a[i]]:=i;

            first[a[i]]:=i;

        end;

end;

 

procedure add(x:longint);

begin

    while x<=n do

    begin

        c[x]:=c[x]+1;

        x:=x+(x and (-x));

    end;

end;

 

function ask(x:longint):longint;

begin

    ask:=0;

    while x>0 do

    begin

        ask:=ask+c[x];

        x:=x-(x and (-x));

    end;

end;

 

procedure main;

var

    i, j                :longint;

    ll                  :longint;

begin

    for i:=1 to tot do if first[i]<>0 then add(first[i]);

    ll:=1;

    for i:=1 to m do

    begin

        for j:=ll to l[i]-1 do if other[j]<>0 then add(other[j]);

        ans[i]:=ask(r[i])-ask(l[i]-1);

        ll:=l[i];

    end;

    qs1(1,m);

    for i:=1 to m do writeln(ans[i]);

end;

 

begin

    init;

    main;

end.

 

 

 

你可能感兴趣的:(树状数组)