• acdreamoj1108(The kth number)


    题目链接:http://acdream.info/problem?

    pid=1108

    题意:n个数的数列,m次查询某个区间出现次数第k多的数出现的次数。n,m<=100000


    解法:这个由于是离线的所以能够先统一处理,然后再输出。能够维护一个left和right指针。pre,pre[i]表示此时区间内出现次数大于等于i的数的种类。

    为了降低复杂度,关键是left和right的移动方式,即查询区间怎样排序,假设紧靠区间左端点排序,那么右端点每次一定最大回是n。假设依照右端点排序,左端点每次一定最大是n。这里有个非常好的处理办法,就是模糊排序。先左端点非严格排序。即除以sqrt(n)再排序,这样复杂度最大是n*sqrt(n)


    代码:

    /******************************************************
    * @author:xiefubao
    *******************************************************/
    #pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #include <set>
    #include <stack>
    #include <string.h>
    //freopen ("in.txt" , "r" , stdin);
    using namespace std;
    
    #define eps 1e-8
    #define zero(_) (abs(_)<=eps)
    const double pi=acos(-1.0);
    typedef long long LL;
    const int Max=100010;
    const int INF=1e9+7;
    
    int num[Max];
    int help[Max];
    int r[Max];
    int l[Max];
    int k[Max];
    int pre[Max];
    int cnt[Max];
    int tool;
    bool cmp(int i,int j)
    {
        if(l[i]/tool==l[j]/tool&&r[i]!=r[j])
            return r[i]<r[j];
        return l[i]<l[j];
    }
    int ans[Max];
    int n,m;
    int findans(int t)
    {
        int l=1,r=n;
        while(l<=r)
        {
            int middle=(l+r)/2;
            if(pre[middle]>=t)
            l=middle+1;
            else
                r=middle-1;
        }
        return l-1;
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            scanf("%d%d",&n,&m);
            tool=sqrt(n);
            for(int i=0; i<n; i++)
                scanf("%d",num+i),help[i]=i;
            for(int i=0; i<m; i++)
                scanf("%d%d%d",l+i,r+i,k+i),l[i]--,r[i]--;
            sort(help,help+m,cmp);
            memset(cnt,0,sizeof cnt);
            memset(pre,0,sizeof pre);
            int left=0,right=-1;
            for(int i=0;i<m;i++)
            {
               int L=l[help[i]],R=r[help[i]];
               while(left<L){ pre[cnt[num[left++]]--]--;}
               while(L<left){ pre[++cnt[num[--left]]]++;}
               while(right<R){ pre[++cnt[num[++right]]]++;}
               while(R<right){ pre[cnt[num[right--]]--]--;}
               ans[help[i]]=findans(k[help[i]]);
            }
            for(int i=0;i<m;i++)
                printf("%d
    ",ans[i]);
        }
        return 0;
    }
    

  • 相关阅读:
    数据库与数据仓库的区别
    MySQL数据库与表的最基本命令大盘点
    SQL Server 2008创建数据库
    [HttpClient]简单使用GET请求
    [HttpClient]HttpClient简介
    [jQuery编程挑战]003 克隆一个页面元素及其相关事件
    [设计模式]观察者模式
    [jQuery编程挑战]002:实现一个转盘大抽奖
    [设计模式]备忘录模式
    [javascript]String添加trim和reverse方法
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5357921.html
Copyright © 2020-2023  润新知