bzoj 2821 分类: bzoj 2015-08-07 18:38 11人阅读 评论(0) 收藏


因为强制在线,所以无法用莫队算法。。。

将序列分块,设块的大小为 X

首先预处理出第 i 块到第 j 块的答案,复杂度O(N2X)

然后对于每个询问,我们对整块以外的数重新计算对答案的贡献即可。
时间复杂度 O(NXlogN)

根据基本不等式,每块的大小为 N/logN

时间复杂度:O(MNlogN)


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
    return;
}
template<class Num>void write(Num x)
{
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    if(!sl) {putchar('0');return;}
    while(sl) putchar(s[--sl]);
}

const int maxn = 1e5+5, maxc = maxn, maxm = maxn;
const int maxs = 1308;
const double eps = 1e-5;
#define clear(__arr) memset(__arr, 0, sizeof(__arr))
#define Check(x) ((x && !(x&1))?1:0) 

int n, c, m, a[maxn], ans;
int block, size, block_cnt[maxs][maxs];
int cnt[maxc], odd;
int arr[maxn], len; 

int cur[maxc], vec[maxn];

void init()
{
    read(n), read(c), read(m);
    for(int i = 1; i <= n; i++) read(a[i]);
}
void add(int t,int val)
{
    odd -= Check(cnt[a[t]]);

    cnt[a[t]] += val;

    odd += Check(cnt[a[t]]);
}
void prework()
{
    int l, r, st, ed;

    block = (n != 1)?(sqrt((double)n/log(n)*log(2))+eps):1;
    size = n/block + ((n%block)?1:0);

    odd = 0, l = 1, r = 1, add(1, 1);   

    for(int i = 1; i <= size; i++)
        for(int j = i; j <= size; j++)
        {
            st = block*(i - 1) + 1;
            ed = std::min(block*j, n);

            while(l > st) --l, add(l, 1);
            while(r < ed) ++r, add(r, 1);

            while(l < st) add(l, -1), l++;
            while(r > ed) add(r, -1), r--;

            block_cnt[i][j] = odd;
        }
    clear(cnt); 

    for(int i = 1; i <= n; i++) cur[a[i]]++;

    for(int i = 1; i <= c; i++) cur[i] += cur[i-1];

    for(int i = n; i >= 1; i--) vec[cur[a[i]]--] = i;

    cur[c + 1] = n; 
}
#define GetNum(fr,to,val) (std::upper_bound(vec + cur[val] + 1, vec + cur[val + 1] + 1, to) - std::lower_bound(vec + cur[val] + 1, vec + cur[val + 1] + 1, fr))

void solve()
{
    int l, r, st, ed, count;
    int l_block, r_block;

    for(int Case = 1; Case <= m; Case ++)
    { 
        read(l), read(r);
        l = (l + ans)%n + 1;
        r = (r + ans)%n + 1;
        if(l > r) std::swap(l, r);

        ans = 0;

        l_block = (l - 1)/block + 1;
        r_block = (r - 1)/block + 1;

        if(r_block - l_block <= 1)
        {
            for(int i = l; i <= r; i++) cnt[a[i]]++, arr[++len] = a[i];

            std::sort(arr + 1, arr + len + 1);
            len = std::unique(arr + 1, arr + len + 1) - (arr + 1);

            for(int i = 1; i <= len; i++)
                ans += Check(cnt[arr[i]]), cnt[arr[i]] = 0;

            len = 0;
        }
        else
        {
            st = block*l_block + 1, ed = block*(r_block - 1);

            ans = block_cnt[l_block+1][r_block-1];

            for(int i = l; i < st; i++) arr[++len] = a[i];
            for(int i = r; i > ed; i--) arr[++len] = a[i];

            std::sort(arr + 1, arr + len + 1);
            len = std::unique(arr + 1, arr + len + 1) - (arr + 1);

            for(int i = 1; i <= len; i++)
            {   
                count = GetNum(st, ed, arr[i]), ans -= Check(count);
                count = GetNum(l, r, arr[i]), ans += Check(count);

                arr[i] = 0;
            }   
            len = 0;
        }

        write(ans), puts("");
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("2821.in","r",stdin);
    freopen("2821.out","w",stdout);
#endif

    init(), prework(), solve();

#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2015-08-07 18:38  <Dash>  阅读(125)  评论(0编辑  收藏  举报