[POJ 2104] K-th Number (块状数组)

来源:互联网 发布:mac记事本 编辑:程序博客网 时间:2024/04/29 23:58

POJ - 2104
给定一个长度为 N的互不相同的序列和 M个询问
每次询问给出一个区间,问区间内第 K大的数是多少

分块做法:
将区间分块,每块大小 sqrt(n),分块内排序
每次查询一个第 K大,先二分确定这个数是多少
然后在区间内统计小于他的数有多少个,如果 cnt>=K,则缩小这个数 (log(n))
统计方式是,每次查询的一个区间
如果完全包含了一个分块,则在分块内二分搜索 (n/sqrt(n)=sqrt(n))
而不完全包含分块的部分,则暴力地一个个查找 (sqrt(n))
时间复杂度 O(m*log(n)*sqrt(n))

分块第一题,说一下感想:
1) 要注意分块的时候,右边界的处理,他可能会超过 N,要判断下
2) 关于为什么块的大小是 bsiz=sqrt(n)
很显然,每次查询的复杂度是 n/bsiz + bsiz,由基本不等式可得
当 bsiz=sqrt(n)的时候,这个复杂度有最小值 sqrt(n)

关于这题的一些坑点:
1) 二分查找的时候,不是在 [-INF, INF]范围查找,而是对原数组排序,在原数组里查找值
2) 这题分块的大小要强制限定为 1000,不要问我为啥不是 sqrt(n),因为玄学

#include <cstdio>#include <iostream>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <map>#include <set>#include <queue>using namespace std;typedef pair<int,int> Pii;typedef long long LL;typedef unsigned long long ULL;typedef double DBL;typedef long double LDBL;#define MST(a,b) memset(a,b,sizeof(a))#define CLR(a) MST(a,0)#define Pow2(a) (a*a)const int maxn=1e5+10,INF=1e9+10;int N,M,bsiz;int inpt[maxn];int sarr[maxn];int arry[maxn];template<typename T> inline void read(T &x){    x = 0; T f = 1; char ch = getchar();    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}    while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}    x *= f;}int Cnt(int,int,int);int main(){//  #ifdef LOCAL//  freopen("in.txt", "r", stdin);//  freopen("out.txt", "w", stdout);//  #endif    while(~scanf("%d%d", &N, &M))    {        for(int i=0; i<N; i++)        {            scanf("%d", &inpt[i]);            sarr[i]=inpt[i];        }        sort(sarr,sarr+N);//      bsiz=sqrt(N);        bsiz=1000;        int front=0;        while(front<N)        {            int rear=front+bsiz;            if(rear>=N) rear=N;            for(int i=front; i<rear; i++) arry[i]=inpt[i];            sort(arry+front,arry+rear);            front=rear;        }        int x,y,k;        for(int i=1; i<=M; i++)        {            scanf("%d%d%d", &x, &y, &k);            int l=0,r=N-1;            while(l<r)            {                int mid=(l+r+1)>>1;                if(Cnt(x-1,y,sarr[mid])>=k) r=mid-1;                else l=mid;            }            printf("%d\n", sarr[l]);        }    }    return 0;}int Cnt(int ql, int qr, int num){    int np=ql,tcnt=0;    while(np<qr)    {        int pos=np/bsiz,bl=pos*bsiz,br=pos*bsiz+bsiz;        if(ql<=bl&&br<=qr) tcnt+=lower_bound(arry+bl,arry+br,num)-(arry+bl);        else        {            int l=max(ql,bl),r=min(br,qr);            for(int i=l; i<r; i++)            {                if(inpt[i]<num) tcnt++;            }        }        np=br;    }    return tcnt;}
0 0
原创粉丝点击