ACdream 1108 分块

来源:互联网 发布:macbookpro必装软件 编辑:程序博客网 时间:2024/04/30 10:24

题意:给定一个数列,然后有一堆的询问,问在闭区间[l,r]中出现了至少k次的多少个数

解法:对区间的数的出现次数分块 一共分成sqrt(n)块 对于所有在同一个块中的元素而言,它的左边最多滑动sqrt(n),右边最多滑动n 那么就是n*sqrt(n);

对于不同块的而言 最多出现sqrt(n)对 也就是边界 而每一对的左边最多滑动n右边最多滑动n 也是n*sqrt(n)

也就是总体复杂度都在n*sqrt(n)

但是对于这个问题还有需要对频率进行查询 那么我们采用二分 也还是 n*sqrt(n)

#include<cstdio>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>#include<cmath>using namespace std;#define maxn 111111#define sqr (350)#define mid ((l+r)>>1)int cnt[maxn],fre[maxn],a[maxn],ll[maxn],rr[maxn],kk[maxn],id[maxn];int ans[maxn];int n,m;int cmp(int x,int y){    if(ll[x]/sqr==ll[y]/sqr){        return rr[x]<rr[y];    }else return ll[x]<ll[y];}int bin(int fr){    int l=1,r=100001;    int ans=1;    while(l<=r){        if(fre[mid]>=fr){ans=mid;l=mid+1;}        else r=mid-1;    }return ans;}int main(){    int _;scanf("%d",&_);    while(_--){        scanf("%d%d",&n,&m);        for(int i=0;i<n;++i)scanf("%d",&a[i]);        for(int i=0;i<m;++i){            scanf("%d%d%d",&ll[i],&rr[i],&kk[i]);--ll[i],--rr[i];            id[i]=i;        }        sort(id,id+m,cmp);                memset(cnt,0,sizeof cnt);        memset(fre,0,sizeof fre);        int nowl=0,nowr=-1;                for(int i=0;i<m;++i){            int l=ll[id[i]],r=rr[id[i]],k=kk[id[i]];                        while(nowr<r)fre[++cnt[a[++nowr]]]++;            while(nowl>l)fre[++cnt[a[--nowl]]]++;            while(nowl<l)fre[cnt[a[nowl++]]--]--;            while(nowr>r)fre[cnt[a[nowr--]]--]--;            ans[id[i]]=bin(k);        }        for(int i=0;i<m;++i)printf("%d\n",ans[i]);            }    return 0;}


0 0
原创粉丝点击