【BZOJ 2724】 蒲公英

【题目链接】

            https://www.lydsy.com/JudgeOnline/problem.php?id=2724

【算法】

            分块算法在线维护区间众数

            分块算法的精髓就在于 : 大段维护,局部朴素

            这一题,我们可以将序列分成T段,那么每一段的长度就是(N/T)

            对于每个询问,设l处于第p段,r处于第q段,那么 :

            若p = q,用朴素算法计算出区间众数即可

            否则,将这个序列分为三段 :

            1.[L,R[p]] 2. [L[p+1],R[q-1]] 3. [L[q],r]

            显然,区间众数只可能是 [L[p+1],R[q-1]]中的众数或[L,R[p]]中的一个数,或[L[q],r]中的一个数

            不妨预处理所有以“段边界”为端点每个数出现的次数和区间众数

    当T取sqrt3(N)(开三次方)时,时间复杂度是非常优秀的 : O(n^(5/3))

【代码】

           

#include<bits/stdc++.h>
using namespace std;
#define MAXN 40010
const int INF = 2e9;

int i,j,k,n,m,l,r,l0,r0,lastans,t,block,len;
int a[MAXN],val[MAXN],L[42],R[42],pos[MAXN],rk[MAXN];
int cnt[42][42][MAXN],mx[42][42],d[42][42];

inline int query(int l,int r)
{
        int i;
        static int sum[MAXN];
        int mx = 0,ret = 0;
        int p = pos[l],q = pos[r];
        if (p == q)
        {
                for (i = l; i <= r; i++)
                {
                        sum[rk[i]]++;
                         if (sum[rk[i]] > mx || (sum[rk[i]] == mx && rk[i] < ret))
                         {
                                 mx = sum[rk[i]];
                                 ret = rk[i];
                         }
                }        
                for (i = l; i <= r; i++) sum[rk[i]]--;
                return ret;
        }    else
        {
                ret = d[p+1][q-1];
                mx = cnt[p+1][q-1][ret];
                for (i = l; i <= R[p]; i++) 
                {
                        cnt[p+1][q-1][rk[i]]++;
                        if (cnt[p+1][q-1][rk[i]] > mx || (cnt[p+1][q-1][rk[i]] == mx && rk[i] < ret))
                        {
                                mx = cnt[p+1][q-1][rk[i]];
                                ret = rk[i];
                        }
                 }
                for (i = L[q]; i <= r; i++)
                {
                        cnt[p+1][q-1][rk[i]]++;
                        if (cnt[p+1][q-1][rk[i]] > mx || (cnt[p+1][q-1][rk[i]] == mx && rk[i] < ret))
                        {
                                mx = cnt[p+1][q-1][rk[i]];
                                ret = rk[i];
                        }
                }
                for (i = l; i <= R[p]; i++) cnt[p+1][q-1][rk[i]]--;
                for (i = L[q]; i <= r; i++) cnt[p+1][q-1][rk[i]]--;
                return ret;
        }
} 
 
int main() 
{
        
        scanf("%d%d",&n,&m);
        for (i  = 1; i <= n; i++)
        {
                scanf("%d",&a[i]);
                val[++len] = a[i];
        }
        sort(val+1,val+len+1);
        len = unique(val+1,val+len+1) - val - 1;
        for (i = 1; i <= n; i++) rk[i] = lower_bound(val+1,val+len+1,a[i]) - val;
        block = (int)pow(n*1.0,1.0/3);
        if (block) t = n / block;
        for (i = 1; i <= block; i++)
        {
                L[i] = (i - 1) * t + 1;
                R[i] = i * t;
        }
        if (R[block] < n)
        {
                block++;
                L[block] = R[block-1] + 1;
                R[block] = n;
        }
        for (i = 1; i <= block; i++)
        {
                for (j = L[i]; j <= R[i]; j++)
                {
                        pos[j] = i;
                }
        }
        for (i = 1; i <= block; i++)
        {
                for (j = i; j <= block; j++)
                {
                        for (k = L[i]; k <= R[j]; k++)
                                cnt[i][j][rk[k]]++;
                        for (k = 1; k <= len; k++)
                        {
                                if (cnt[i][j][k] > mx[i][j] || (cnt[i][j][k] == mx[i][j] && k < d[i][j]))
                                {
                                        mx[i][j] = cnt[i][j][k];
                                        d[i][j] = k;
                                }
                        }
                }        
        }
        lastans = 0;
        for (i = 1; i <= m; i++)
        {
                scanf("%d%d",&l0,&r0);
                l = (l0 + lastans - 1) % n + 1; 
                r = (r0 + lastans - 1) % n + 1;
                if (l > r) swap(l,r);
                printf("%d\n",lastans = val[query(l,r)]);            
        }
        
        return 0;
    
}

 

posted @ 2018-07-14 14:42  evenbao  阅读(142)  评论(0编辑  收藏  举报