POJ2104 K-th Number [分块做法]

Posted Candy?

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ2104 K-th Number [分块做法]相关的知识,希望对你有一定的参考价值。

传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html


 

做那倒带修改的主席树时就发现分块可以做,然后就试了试

思想和教主的魔法差不多,只不过那个是求>=v的有几个

既然一个数v的名次可以求,我们二分这个数就行了啊

然而......

首先,你二分到的这个数不一定在区间里出现过

比如 1 2 5 8 9

4和5的名次都是3

于是,我修改了某个区间名次的定义:

“如果一个数的名次是x,但是区间中没有次数,那么他的名次为x-1”

实现上只需要find里return l-t+(b[l]==v) 等于说明出现过

然而


 


 


 


 

该死不写了鬼知道怎么回事用主席树就行了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=1e5+500;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<\'0\'||c>\'9\'){if(c==\'-\')f=-1; c=getchar();}
    while(c>=\'0\'&&c<=\'9\'){x=x*10+c-\'0\'; c=getchar();}
    return x*f;
}
int n,Q,a[N],bl,m,b[N],pos[N];
int mp[N];
void reset(int x){
    int l=(x-1)*bl+1,r=min(x*bl,n);
    for(int i=l;i<=r;i++) b[i]=a[i];
    sort(b+l,b+r+1);
}
int flag;
int find(int x,int v){
    int l=(x-1)*bl+1,r=min(x*bl,n),t=l;
    while(l<=r){
        int mid=(l+r)>>1;
        if(b[mid]<v) l=mid+1;
        else r=mid-1;
    }
    if(b[l]==v) flag=1;
    return l-t+1;//!
}
int rank(int l,int r,int v){
    int ans=0;
    flag=0;
    if(pos[l]==pos[r]){
        for(int i=l;i<=r;i++) if(a[i]<=v) ans++,flag=flag||a[i]==v;
    }else{
        int t=pos[l]*bl;
        for(int i=l;i<=t;i++) if(a[i]<=v) ans++,flag=flag||a[i]==v;
        for(int i=(pos[r]-1)*bl+1;i<=r;i++) if(a[i]<=v) ans++,flag=flag||a[i]==v;
        for(int i=pos[l]+1;i<pos[r];i++) ans+=find(i,v);
    }
    if(!flag) ans--;
    return ans;
}
int query(int ql,int qr,int k){
    int l=1,r=n;
    while(l<=r){
        int mid=(l+r)>>1;
        int t=rank(ql,qr,mp[mid]);
        if(t<k) l=mid+1;
        else r=mid-1;
    }
    return l;
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("1.out","w",stdout);
    n=read();Q=read();
    bl=sqrt(n);
    m=n/bl;if(n%bl) m++;
    for(int i=1;i<=n;i++) a[i]=mp[i]=read(),pos[i]=(i-1)/bl+1;
    for(int i=1;i<=m;i++) reset(i);
    sort(mp+1,mp+1+n);
    while(Q--){
        int i=read(),j=read(),k=read();
        printf("%d\\n",mp[query(i,j,k)]);
    }
}
View Code
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          1000005
#define   maxnode       15
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
const double inf   = 1e18;
const double eps   = 1e-8;
const LL    mod    = 1e9+7;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<\'0\' || c>\'9\');
      x=c-\'0\';
      while((c=getchar())>=\'0\' && c<=\'9\') x=(x<<3)+(x<<1)+c-\'0\';
 }
/*****************************************************/

int a[MAX];
int b[MAX];
int c[MAX];
int tmp;
bool judge(int x,int l,int r,int k){
    int a1=l/tmp;
    int a2=r/tmp;
    int sum=0;//for(int i=l;i<=r;i++) printf("%d ",a[i]);puts("");
    if(a1==a2){
        for(int i=l;i<=r;i++) if(a[i]<=c[x]) sum++;
        if(sum>=k) return true;
        return false;
    }
    for(int i=a1+1;i<a2;i++){
        sum+=upper_bound(b+i*tmp,b+(i+1)*tmp,c[x])-b-i*tmp;
    }
    for(int i=l;i<(a1+1)*tmp;i++) if(a[i]<=c[x]) sum++;
    for(int i=a2*tmp;i<=r;i++) if(a[i]<=c[x]) sum++;
    
    //printf("ra %d %d %d %d\\n",l,r,c[x],sum);
    if(sum>=k) return true;
    return false;
}

int main(){
    freopen("in.txt","r",stdin);
    freopen("2.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    tmp=sqrt(n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        b[i]=a[i];
        c[i]=a[i];
    }
    sort(c,c+n);
    for(int i=0;i*tmp<n;i++){
        if((i+1)*tmp<=n) sort(b+i*tmp,b+(i+1)*tmp);
        else sort(b+i*tmp,b+n);
    }
    while(m--){
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        int ll=0,rr=n-1;
        while(ll<=rr){
            int mid=(ll+rr)>>1;
            if(judge(mid,l-1,r-1,k)) rr=mid-1;
            else ll=mid+1;
        }
        printf("%d\\n",c[ll]);
    }
    return 0;
}
别人的AC代码

 

以上是关于POJ2104 K-th Number [分块做法]的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2104 K-th Number ( 求取区间 K 大值 )

[POJ2104] K-th Number(归并树)

POJ - 2104 K-th Number

POJ 2104 K-th Number

POJ2104 K-th Number(主席树)

poj[2104]K-th Number