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.

 

 

 

posted on 2013-12-08 21:01  BLADEVIL  阅读(331)  评论(0编辑  收藏  举报