• #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;
    }
  • 相关阅读:
    我心里优秀架构师是怎样的?
    Rock Pi开发笔记(一):Rock Pi系列arm产品方案快速落地方案介绍
    面试官:Redis中有序集合的内部实现方式是什么?
    面试官:Java中对象都存放在堆中吗?你知道逃逸分析?
    多线程设计模式之保护性暂停
    多线程之深入理解park与unpark
    模拟实现FutureTask
    多线程之park()与interrupt()的理解
    多线程之活锁(了解一下就可以了)
    多线程之模拟自定义消息队列
  • 原文地址:https://www.cnblogs.com/xiongtao/p/9819170.html
Copyright © 2020-2023  润新知