蒲公英

题目描述

亲爱的哥哥: 
你在那个城市里面过得好吗? 
我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!
它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤
出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的…… 
最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了
呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢!  
哥哥你要快点回来哦! 
                                                                           爱你的妹妹 Violet 
Azure 读完这封信之后微笑了一下。 
“蒲公英吗……” 
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。 
为了简化起见,我们把所有的蒲公英看成一个长度为 n 的序列 (a1,a2,a3,...,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

在线求区间内的众数

分块
pre[i][j]表示在第i块(包括第i块)之前j这个数出现的次数
f[i][j]记录第i块到第j块这段区间内的众数及其出现的次数
(书上给的做法是用一个vector记录每个数在这个序列中出现的位置,然后在vector中lower_bound一下就可以求出出现次数,但是疯狂TLE)

对每次询问a,b
答案要么是bl[a]+1~bl[b]-1这些块的众数,要么是a~bl[a]*blo或者bl[b]-1~b之内的某个数

预处理是n*sqrt(n),询问是sqrt(n)
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5;
map<int,int>mp;
int n,m,blo,id;
int bl[N],v[N],cnt[N],val[N],pre[205][N];
struct orz{
    int val,cnt;}f[205][205];
void does()
{
    for (int i=1;i<=bl[n];i++)
    {
        for (int j=1;j<=id;j++) pre[i][j]=pre[i-1][j];
        for (int j=(i-1)*blo+1;j<=i*blo&&j<=n;j++) pre[i][v[j]]++;
    }

    for (int l=1;l<=bl[n];l++)
    for (int r=l;r<=bl[n];r++)
    {
        f[l][r]=f[l][r-1];
        orz now=f[l][r];
        for (int i=(r-1)*blo+1;i<=r*blo&&i<=n;i++)
        {
            if (pre[r][v[i]]-pre[l-1][v[i]]>now.cnt || pre[r][v[i]]-pre[l-1][v[i]]==now.cnt&&val[v[i]]<val[now.val])
            {
                now.val=v[i];
                now.cnt=pre[r][v[i]]-pre[l-1][v[i]];
            }
        }
        f[l][r]=now;
    }
}

int ask(int a,int b)
{
    orz ans=f[bl[a]+1][bl[b]-1];

    for (int i=a;i<=bl[a]*blo&&i<=b;i++)
    {
        cnt[v[i]]++;
        int t=cnt[v[i]]+max(pre[bl[b]-1][v[i]]-pre[bl[a]][v[i]],0);
        if (t>ans.cnt||t==ans.cnt&&val[v[i]]<val[ans.val]) ans.val=v[i],ans.cnt=t;
    }

    if (bl[a]!=bl[b])
    {
        for (int i=(bl[b]-1)*blo+1;i<=b;i++)
        {
            cnt[v[i]]++;
            int t=cnt[v[i]]+max(pre[bl[b]-1][v[i]]-pre[bl[a]][v[i]],0);
            if (t>ans.cnt||t==ans.cnt&&val[v[i]]<val[ans.val]) ans.val=v[i],ans.cnt=t;
        }
    }

    for (int i=a;i<=bl[a]*blo&&i<=b;i++) cnt[v[i]]--;
    if (bl[a]!=bl[b])
         for (int i=(bl[b]-1)*blo+1;i<=b;i++) cnt[v[i]]--;

    return ans.val;
}
int main()
{
    scanf("%d%d",&n,&m);
    blo=200;
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]);
        if (!mp[v[i]])
        {
            mp[v[i]]=++id;
            val[id]=v[i];
        }
        v[i]=mp[v[i]];
    }

    for (int i=1;i<=n;i++) bl[i]=(i-1)/blo+1;
    does();

    int ans=0,a,b;
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        a=(a+ans-1)%n+1; b=(b+ans-1)%n+1;
        if (a>b) swap(a,b);
        ans=val[ask(a,b)];
        printf("%d
",ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/tetew/p/9748235.html