分块莫队


分块

结合二分查找和

??“蒲公英吗……”

??在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。

??为了简化起见,我们把所有的蒲公英看成一个长度为 n 的序列 (),其中  为一个正整数,表示第 i 棵蒲公英的种类编号。

??而每次询问一个区间[l, r],你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。

注意,你的算法必须是在线的。

输入格式

第一行两个整数 n, m,表示有 n 株蒲公英,m 次询问。

接下来一行 n 个空格分隔的整数 ,表示蒲公英的种类。

再接下来 m 行每行两个整数 ,我们令上次询问的结果为 x(如果这是第一次询问,则 x = 0)。

令 ,如果 l > r,则交换 l, r。

最终的询问区间为[l, r]。

输出格式

输出 m 行。每行一个整数,表示每次询问的结果。

const int N=4e4+100;
int n,m,a[N],map_a[N],map_n;
int cnt,l[300],r[300],pos[N];
vector<int>data[N];
int a_cnt[N],fast[300][300],fast_cnt[300][300],x;
int vis[N];
inline int baoli(int l0,int r0)
{
    memset(a_cnt,0,sizeof(a_cnt));int pot=0,pot_cnt=0;
    _f(k,l0,r0)
    {
        a_cnt[map_a[k]]++;
        if(map_a[k]==pot)pot_cnt++;
        else if(a_cnt[map_a[k]]==pot_cnt)
        {
            if(map_a[k]a_cnt[map_a[k]];
        }
        else if(a_cnt[map_a[k]]>pot_cnt)
        {
            pot=map_a[k],pot_cnt=a_cnt[map_a[k]];
        }
    }
    return pot;
}
inline int erfen(int pot,int l,int r)
{
    int ll=0;int rr=data[pot].size()-1;//都代表data的下标位置
    while(data[pot][ll]<l)
    ll++;
    while(data[pot][rr]>r)
    rr--;
    return rr-ll+1;
}
inline void solve()
{
    int l0=re(),r0=re();
    l0=(l0+x-1)%n+1,r0=(r0+x-1)%n+1;
    if(l0>r0)swap(l0,r0);
    if(l0==r0)
    {
        x=map_a[l0];
        x=a[x];
        chu("%d\n",x);
        return;
    }
    if(pos[l0]==pos[r0])
    {
        x=baoli(l0,r0);
        x=a[x];
        chu("%d\n",x);
        return;
    }
    int k_l0=pos[l0],k_r0=pos[r0];
    if((l[k_l0]==l0)&&(r[k_r0]==r0))
    {
        x=fast[k_l0][k_r0];
        x=a[x];
        chu("%d\n",x);
        return;
    }
    memset(vis,0,sizeof(vis));
    //中间取出来一个众数,两头暴力 扫描
    int pot=fast[k_l0+1][k_r0-1],pot_cnt=fast_cnt[k_l0+1][k_r0-1];//那这数字是多少呢?
    _f(i,l0,l[k_l0+1]-1)
    {
        if(vis[map_a[i]])continue;
        vis[map_a[i]]=1;
        int maybe=erfen(map_a[i],l0,r0);
        if(maybe>pot_cnt)pot=map_a[i],pot_cnt=maybe;
        else if((maybe==pot_cnt)&&(map_a[i]maybe;
        else if(maybe>pot_cnt)pot=map_a[i],pot_cnt=maybe;
    }
    _f(i,r[k_r0-1]+1,r0)
    {
        if(vis[map_a[i]])continue;
        vis[map_a[i]]=1;
        int maybe=erfen(map_a[i],l0,r0);
        if(maybe>pot_cnt)pot=map_a[i],pot_cnt=maybe;
        else if((maybe==pot_cnt)&&(map_a[i]maybe;
        else if(maybe>pot_cnt)pot=map_a[i],pot_cnt=maybe;
    }
    x=pot;x=a[x];
    chu("%d\n",x);
    return;
}
void datamake()
{
    _f(i,1,n)
    {
        data[map_a[i]].push_back(i);
    }
}
 int main()
{
//    freopen("exam.txt","r",stdin);
    n=re();    m=re();
    _f(i,1,n)
    {
        a[i]=re();map_a[i]=a[i]; 
    }
    sort(a+1,a+1+n);//
    map_n=unique(a+1,a+1+n)-a-1;
    _f(i,1,n)
    {
        map_a[i]=lower_bound(a+1,a+1+map_n,map_a[i])-a;
    //    chu("map[%d]:%d\n",i,map_a[i]);
    }
    cnt=sqrt(n);
    _f(i,1,cnt)
    l[i]=cnt*(i-1)+1,r[i]=cnt*i;
    if(r[cnt]1]+1,r[cnt]=n;//这仅仅代表一个块
    _f(i,1,cnt)
    {
        _f(j,l[i],r[i])pos[j]=i;
    }
    _f(i,1,cnt)//从哪个块开始
    {
        memset(a_cnt,0,sizeof(a_cnt));
        int pot=0,pot_cnt=0;//最大众数,出现次数
        int st=l[i],en=r[i];
        _f(k,st,en)
        {
            a_cnt[map_a[k]]++;
            if(map_a[k]==pot)pot_cnt++;
            else if(a_cnt[map_a[k]]==pot_cnt)
            {
                if(map_a[k]a_cnt[map_a[k]];
            }
            else if(a_cnt[map_a[k]]>pot_cnt)
            {
                pot=map_a[k],pot_cnt=a_cnt[map_a[k]];
            }
        }
        fast[i][i]=pot;fast_cnt[i][i]=pot_cnt;
        _f(j,i+1,cnt)//截至哪个块
        {
            st=l[j],en=r[j];
            _f(k,st,en)
            {
                a_cnt[map_a[k]]++;
                if(map_a[k]==pot)pot_cnt++;
                else if(a_cnt[map_a[k]]==pot_cnt)
                {
                if(map_a[k]a_cnt[map_a[k]];
                }
                else if(a_cnt[map_a[k]]>pot_cnt)
                {
                    pot=map_a[k],pot_cnt=a_cnt[map_a[k]];
                }
            }
            fast[i][j]=pot;fast_cnt[i][j]=pot_cnt;
        }
    }//还要处理出来data
    datamake();

//    chu("m:%d\n",m);
    for(register int i=1;i<=m;i++)
    {
        //chu("route:%d\n",i);
        solve();
    }

    return 0;
}
/*
先离散化
分块,q[i][j]存i块,j类蒲公英的出现次数
maxx[i][j]:处在i--j块里面的众数 ,直接大暴力
每个询问{x,y}
处在同一块:遍历:纯二分
不同块, 遍历,二分找呗

6 3 
1 2 3 2 1 2 
1 5 
3 6 
1 5 
*/