zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",c[ll]);
        }
        return 0;
    }
    别人的AC代码
  • 相关阅读:
    编译Android系统源码和内核源码
    Ubuntu中的解压缩文件的方式
    将秒数转换为基于00:00的时间
    git sshkeygen Fingerprint cannot be generated解决方法
    git bash下的选择、复制、粘贴
    mac 配置jdk maven
    自定义标签
    垃圾收集器和收集算法
    多线程并发中的同步
    现在有T1、T2、T3三个线程,怎样保证T2在T1执行完后执行,T3在T2执行完后执行?使用Join
  • 原文地址:https://www.cnblogs.com/candy99/p/6195716.html
Copyright © 2011-2022 走看看