bzoj2724 [Violet 6]蒲公英

2724: [Violet 6]蒲公英

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 2706  Solved: 950
[Submit][Status][Discuss]

Description

Input

修正一下

l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1

Output

Sample Input

6 3
1 2 3 2 1 2
1 5
3 6
1 5

Sample Output

1
2
1

HINT

n <= 40000, m <= 50000

Source

Vani原创

分析:经典题.

   如果没有强制在线,就可以用莫队算法解决了. 能够利用莫队算法这一事实提供了一个思路:根号算法.

   还有哪些根号算法呢?可以分块!首先有一个结论:区间[l,r]的众数一定是[l,r]整块的众数或者是不在整块的数. 一个想法就是预处理出f数组,f[i][j]表示第i块到第j块的众数.  枚举左端点,维护一个桶就能够预处理出来了.  

   怎么求区间[l,r]出现了多少次a呢? 前缀和?空间不够. 一个可行的方法是对块进行前缀和,然后枚举不在整块内的元素,用一个桶维护每个值出现的次数.  有一个更好的方法:开一个vector数组,第i个vector存着权值为i的下标. 每次upper_bound,lower_bound找下标正好在[l,r]的个数就好了. 

#include <vector>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
const ll maxn = 50010;
ll n,m,a[maxn],b[maxn],tot[maxn],cnt,cntt,lastans;
ll pos[maxn],L[maxn],R[maxn],block,f[1010][1010];
vector <ll>e[maxn];

void pre(ll x)
{
    ll ans = 0,tott = 0;
    memset(tot,0,sizeof(tot));
    for (ll i = L[x]; i <= n; i++)
    {
        tot[a[i]]++;
        if (tot[a[i]] > tott || (tot[a[i]] == tott && b[ans] > b[a[i]]))
        {
            ans = a[i];
            tott = tot[a[i]];
        }
        f[x][pos[i]] = ans;
    }
}

ll query(ll l,ll r)
{
    if (pos[l] == pos[r])
    {
        ll ans = 0;
        cntt = 0;
        for (ll i = l; i <= r; i++)
        {
            ll temp = upper_bound(e[a[i]].begin(),e[a[i]].end(),r) - lower_bound(e[a[i]].begin(),e[a[i]].end(),l);
            if (temp > cntt || (temp == cntt && b[a[i]] < b[ans]))
            {
                ans = a[i];
                cntt = temp;
            }
        }
        return ans;
    }
    ll temp = f[pos[l] + 1][pos[r] - 1];
    ll cntt = upper_bound(e[temp].begin(),e[temp].end(),r) - lower_bound(e[temp].begin(),e[temp].end(),l);
    for (ll i = l; i <= R[pos[l]]; i++)
    {
        ll tmp = upper_bound(e[a[i]].begin(),e[a[i]].end(),r) - lower_bound(e[a[i]].begin(),e[a[i]].end(),l);
        if (tmp > cntt || (tmp == cntt && a[i] < temp))
        {
            temp = a[i];
            cntt = tmp;
        }
    }
    for (ll i = L[pos[r]]; i <= r; i++)
    {
        ll tmp = upper_bound(e[a[i]].begin(),e[a[i]].end(),r) - lower_bound(e[a[i]].begin(),e[a[i]].end(),l);
        if (tmp > cntt || (tmp == cntt && a[i] < temp))
        {
            temp = a[i];
            cntt = tmp;
        }
    }
    return temp;
}

int main()
{
    scanf("%lld%lld",&n,&m);
    block = sqrt(n);
    for (ll i = 1; i <= n; i++)
    {
        scanf("%lld",&a[i]);
        b[i] = a[i];
        pos[i] = (i - 1) / block + 1;
    }
    cnt = (n - 1) / block + 1;
    for (ll i = 1; i <= cnt; i++)
    {
        L[i] = R[i - 1] + 1;
        R[i] = min(i * block,n);
    }
    sort(b + 1,b + 1 + n);
    cntt = unique(b + 1,b + 1 + n) - b - 1;
    for (ll i = 1; i <= n; i++)
        a[i] = lower_bound(b + 1,b + 1 + cntt,a[i]) - b;
    for (ll i = 1; i <= n; i++)
        e[a[i]].push_back(i);
    for (ll i = 1; i <= n; i++)
        sort(e[i].begin(),e[i].end());
    for (ll i = 1; i <= cnt; i++)
        pre(i);
    for (ll i = 1; i <= m; i++)
    {
        ll l,r;
        scanf("%lld%lld",&l,&r);
        l = (l + lastans - 1) % n + 1;
        r = (r + lastans - 1) % n + 1;
        if (l > r)
            swap(l,r);
        printf("%lld\n",lastans = b[query(l,r)]);
    }

    return 0;
}

 

 

posted @ 2018-03-13 23:30  zbtrs  阅读(164)  评论(0编辑  收藏  举报