#6285. 数列分块入门 9

题目链接:https://loj.ac/problem/6285

题目描述

给出一个长为 n 的数列,以及 n 个操作,操作涉及询问区间的最小众数。

输入格式

第一行输入一个数字 n

第二行输入 n 个数字,第 i个数字为 ai​​,以空格隔开。

接下来输入 n 行询问,每行输入两个数字 l、r,以空格隔开。

表示查询位于 [l,r] 的数字的众数。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

4
1 2 2 4
1 2
1 4
2 4
3 4

样例输出

1
2
2
2

思路:分块的思维,先将n分块,预处理每两块之间的众数,在用二分求不完整块中每个数是否可能为众数。
这里用id转换数值,将值变成第几个出现的数。
代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<cstdio>
#include<cstring>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int a[maxn],MAX[2020][2020],id,n,block;
int pos[maxn],val[maxn],num[maxn];//pos记录在哪个块,val[i]记录编号为i的原值,num用来求众数 
map<int,int >mp;
vector<int>v[maxn];//储存编号相同,即数相同时的原来的第几个值。用来二分求众数用 
bool visit[maxn];//标记 

void init(int x)//预处理每块之间的众数 
{
    int count=0,max1=0;
    memset(num,0,sizeof(num));
    for(int i=(x-1)*block+1;i<=n;i++)
    {
        num[a[i]]++;
        if(num[a[i]]>count||num[a[i]]==count&&val[a[i]]<val[max1])//找最小众数
        {
            count=num[a[i]];
            max1=a[i];
        }
        MAX[x][pos[i]]=max1;
    }    
} 

int er(int x,int l,int r)//二分查找块内,编号为x的数量
{
    return upper_bound(v[x].begin(),v[x].end(),r)-lower_bound(v[x].begin(),v[x].end(),l);
}

int solve(int l,int r)
{
    int ans=MAX[pos[l]+1][pos[r]-1],count=0;//中间一整块的众数 
    memset(visit,0,sizeof(visit));
    count=er(ans,l,r); 
    visit[ans]=1;
    for(int i=l;i<=min(pos[l]*block,r);i++)//暴力左边不完整块中每个数是否可能为众数
    {
        if(visit[a[i]]==0)
        {
            visit[a[i]]=1;
            int count1=er(a[i],l,r);
            if(count1>count||count1==count&&val[a[i]]<val[ans])
            {
                count=count1;
                ans=a[i];
            }
        }
    }
    if(pos[l]!=pos[r])//暴力右边不完整块中每个数是否可能为众数 
    {
        for(int i=(pos[r]-1)*block+1;i<=r;i++)
        {
            if(visit[a[i]]==0)
            {
                visit[a[i]]=1;
                int count1=er(a[i],l,r);
                if(count1>count||count1==count&&val[a[i]]<val[ans])
                {
                    count=count1;
                    ans=a[i];
                }
            }
        }
    }
    return val[ans];
}
int main()
{
    scanf("%d",&n);
    block=80;
    id=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pos[i]=(i-1)/block+1;
        if(mp[a[i]]==0)
        {
            mp[a[i]]=++id;//id第几个出现的数
            val[id]=a[i];//保存原始值
        }
        a[i]=mp[a[i]];//保存编号(第几个出现的数)
        v[a[i]].push_back(i);
    }
    for(int i=1;i<=pos[n];i++)
        init(i);
    int l,r;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&l,&r);
        printf("%d
",solve(l,r));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xiongtao/p/9819170.html