1. 程式人生 > >NKOJ 2751 蒲公英(分塊)

NKOJ 2751 蒲公英(分塊)

P2751【Violet VI】蒲公英

問題描述

在鄉下的小路旁種著許多蒲公英,而我們的問題正是與這些蒲公英有關。
為了簡化起見,我們把所有的蒲公英看成一個長度為n的序列(a1,a2,a3,a4,…an),
其中ai為一個正整數,表示第i棵蒲公英的種類編號。
而每次詢問一個區間[l,r],你需要回答區間裡出現次數最多的是哪種蒲公英,如果有
若干種蒲公英出現次數相同,則輸出種類編號最小的那個。
注意,你的演算法必須是線上的。

輸入格式

第一行兩個整數n,m,表示有n株蒲公英,m次詢問。
接下來一行 n 個空格分隔的整數ai,表示蒲公英的種類
再接下來m行每行兩個整數l0,r0,我們令上次詢問的結果為x(如果這是第一次詢問,則x=0)。
令l=(l0+x-1)mod n +1,r=(r0+x-1)mod n +1,如果l>r,則交換l,r。
最終的詢問區間為[l,r]。

輸出格式

輸出m行。每行一個整數,表示每次詢問的結果。

樣例輸入

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

樣例輸出

1
2
1

提示

對於 20% 的資料,保證1<=n,m<=3000。
對於 100% 的資料,保證1<=n<=40000,1<=m<=50000,1<=ai<=10^9

區間眾數問題,分塊的經典解法,兩種處理方法

做法一:
分成n13塊,預處理B[i][j]表示第i塊到第j塊的資訊,維護每個數出現的次數,並記錄區間眾數。
查詢的時候,先找到覆蓋的最大整塊區間

[L,R]B[L][R]複製出來,然後將兩邊剩下的數暴力插入。
複雜度O(n53)

做法二:
分成n塊,預處理A[i][j]表示第i塊到第j塊中的眾數,並記錄眾數的出現次數
查詢的時候,同樣找到區間[L,R],答案只可能是A[L][R]或兩側剩下的數,列舉兩側剩下的數,然後查詢一下他在區間中出現的次數,更新答案即可。
關於查詢一個數在區間中的出現次數,可以用vector記下每個數出現位置然後二分查詢,複雜度O(nnlog2n)
或者預處理S[i][j

][k],表示第i塊中,前j個位置,數字k出現次數,SS[i][k],表示前i塊中,數字k出現的次數,然後查詢的時候就可以直接用了(S可以不用處理,每次暴力跑一邊兩邊剩下的數就行了),由於每塊最多n個數,因此預處理的時空複雜度都是O(nn),總時間複雜度也是O(nn)

做法一程式碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 50005
using namespace std;
struct node
{
    int a,b,c[N];
    void Ins(int x)
    {
        c[x]++;
        if(c[x]>b||(c[x]==b&&x<a))a=x,b=c[x];
    }
    void Del(int x){c[x]--;}
}C[40][40],tmp;
int n,m,A[N],B[N],id[N],lp[N],rp[N],S,Cnt;
int GS(int l,int r)
{
    int i,j,k,x,y,p,q;
    if(id[l]==id[r])
    {
        for(i=l;i<=r;i++)tmp.Ins(A[i]);
        k=tmp.a;tmp.a=tmp.b=0;
        for(i=l;i<=r;i++)tmp.Del(A[i]);
        return B[k];
    }
    x=id[l]+1;y=id[r]-1;
    p=C[x][y].a;q=C[x][y].b;
    for(i=l;i<lp[x];i++)C[x][y].Ins(A[i]);
    for(i=rp[y]+1;i<=r;i++)C[x][y].Ins(A[i]);
    k=C[x][y].a;C[x][y].a=p;C[x][y].b=q;
    for(i=l;i<lp[x];i++)C[x][y].Del(A[i]);
    for(i=rp[y]+1;i<=r;i++)C[x][y].Del(A[i]);
    return B[k];
}
int main()
{
    int i,j,k,x,y,ans=0;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)scanf("%d",&A[i]),B[i]=A[i];
    sort(B+1,B+n+1);
    for(i=1;i<=n;i++)A[i]=lower_bound(B+1,B+n+1,A[i])-B;
    S=pow(n,2.0/3);j=1;
    for(i=1;i<=n;i++)
    {
        id[i]=i%S?j:j++;
        if(!lp[id[i]])lp[id[i]]=i;
        rp[id[i]]=max(rp[id[i]],i);
        Cnt=max(Cnt,id[i]);
    }
    for(i=1;i<=Cnt;i++)
    for(j=i;j<=Cnt;j++)
    for(k=lp[i];k<=rp[j];k++)C[i][j].Ins(A[k]);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        x=(x+ans-1)%n+1;
        y=(y+ans-1)%n+1;
        if(x>y)swap(x,y);
        ans=GS(x,y);
        printf("%d\n",ans);
    }
}