bzoj 2821 分块处理

大题思路就是分块,将n个数分成sqrt(n)个块,然后

处理出一个w数组,w[i,j]代表第i个块到第j个块的答案

那么对于每组询问l,r如果l,r在同一个块中,直接暴力做就行了

如果不在同一个块中,l,r区间中整块的部分可以直接由w数组得到答案

然后多出来的部分暴力处理下出现次数,然后再预处理一个b数组,代表没

个数出现的位置,且每个数都连续,那么我们可以二分的找出在多余部分出现的

每个数在整区间内出现多少次,然后和多余部分出现的累加,判断奇偶更新答案

看了lyd的题解,写的挺好(其实这个题就是他出的。。),然后我写的

pascal,他的C++的代码30s+A了,我就TLE了。。。

话说今儿LYD生日,然后SHY发了个说说祝他生日快乐,是我想多了。。。

/**************************************************************
    Problem: 2821
    User: BLADEVIL
    Language: Pascal
    Result: Time_Limit_Exceed
****************************************************************/
 //By BLADEVIL
{$inline on}
var
    n, t, m                     :longint;
    a, b, c                     :array[0..100010] of longint;
    st, ed, s, e, v, q          :array[0..100010] of longint;
    w                           :array[0..400,0..400] of longint;
 
procedure swap(var a,b:longint);inline;
var
    c                           :longint;
begin
    c:=a; a:=b; b:=c;
end;
     
function calc(k,x,y:longint):longint;inline;
var
    l, r, mid                   :longint;
begin
    if x>y then exit(0);
    l:=st[k]; r:=ed[k];
    while l<r do
    begin
        mid:=(l+r+1)>>1;
        if b[mid]<x then l:=mid else r:=mid-1;
    end;
    if b[l]>=x then dec(l);
    x:=l;
    l:=st[k]; r:=ed[k];
    while l<r do
    begin
        mid:=(l+r+1)>>1;
        if b[mid]>y then r:=mid-1 else l:=mid;//
    end;
    if b[l]>y then dec(l);
    y:=l;
    exit(y-x);
end;
     
procedure main;inline;
var
    i, j, k                     :longint;
    p, tot, l, r                :longint;
    now, cnt                    :longint;
    x, y                        :longint;
     
begin  
    read(n,t,m);
    for i:=1 to n do read(a[i]);
    for i:=1 to n do inc(c[a[i]]);
    tot:=0;
    for i:=1 to t do
    begin
        st[i]:=tot+1;
        inc(tot,c[i]);
        ed[i]:=tot;
    end;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do
    begin
        b[st[a[i]]+c[a[i]]]:=i;
        inc(c[a[i]]);
    end;
    p:=trunc(sqrt(n));
    l:=n div p;
    for i:=1 to p do
    begin
        s[i]:=(i-1)*l+1;
        e[i]:=i*l;
    end;
    if e[p]<n then
    begin
        inc(p);
        s[p]:=e[p-1]+1;
        e[p]:=n;
    end;
    for i:=1 to p do
    begin
        fillchar(c,sizeof(c),0);
        now:=0;
        for j:=i to p do
        begin
            for k:=s[j] to e[j] do
            begin
                inc(c[a[k]]);
                if (c[a[k]]>1) and (c[a[k]] and 1<>0) 
                    then dec(now) else
                if (c[a[k]] and 1)=0 then inc(now);
            end;
            w[i,j]:=now;
        end;
    end;
    now:=0;
    for i:=1 to m do
    begin
        read(x,y);
        x:=(x+now) mod n+1;
        y:=(y+now) mod n+1;
        if x>y then swap(x,y);
        for j:=1 to p do
            if x<=e[j] then
            begin
                l:=j;
                break;
            end;
        for j:=p downto 0 do
            if y>=s[j] then
            begin
                r:=j;
                break;
            end;
        now:=w[l+1,r-1];
        if l=r then
        begin
            for j:=x to y do
                if v[a[j]]<>i then
                begin
                    v[a[j]]:=i;
                    c[a[j]]:=1;
                end else
                begin
                    inc(c[a[j]]);
                    if (c[a[j]] and 1)<>0 then
                        dec(now) else inc(now);
                end;
        end else
        begin
            cnt:=0;
            for j:=x to e[l] do
                if v[a[j]]<>i then
                begin
                    v[a[j]]:=i;
                    c[a[j]]:=1;
                    inc(cnt);
                    q[cnt]:=a[j];
                end else inc(c[a[j]]);
            for j:=s[r] to y do
                if v[a[j]]<>i then
                begin
                    v[a[j]]:=i;
                    c[a[j]]:=1;
                    inc(cnt);
                    q[cnt]:=a[j];
                end else inc(c[a[j]]);
            for j:=1 to cnt  do
            begin
                k:=calc(q[j],s[l+1],e[r-1]);
                if k=0 then
                begin
                    if c[q[j]] and 1=0 then inc(now)
                end else
                if (k and 1<>0) and (c[q[j]] and 1<>0) then inc(now) else
                if (k and 1=0) and (c[q[j]] and 1<>0) then dec(now);
            end;
        end;
        writeln(now);
    end;
     
end;
 
 
begin
    main;
end.

 

posted on 2013-12-29 10:24  BLADEVIL  阅读(568)  评论(0编辑  收藏  举报