zoukankan      html  css  js  c++  java
  • 划分树

    看了一晚上hh大牛的划分树,总算看懂了是怎么回事了。。

    hh大牛的博客,请戳这里

    划分树是快排+线段树

    先来一模版 POJ-2104-K-th Number

    题意:给出n,m,n代表N个数,m代表查询的次数,再输入m行l,r,k;求在[l,r]区间中第k小的数;

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MAXN 100050
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    using namespace std;
    int tt[MAXN<<2];//呃,因为不要统计区间的操作,所以这个线段树一般有的数组,现在没有用了。。
    int sorted[MAXN];
    int toLeft[20][MAXN];//20代表的是20层
    int val[20][MAXN];
    void build(int d,int l,int r,int rt){
        if(l==r)return;
        int mid=(l+r)>>1;
        int lsame=mid-l+1;//lsame表示和val_mid相等且分到左边的
        for(int i=l;i<=r;i++){
            if(val[d][i]<sorted[mid]){
                lsame--;//先假设左边的数(mid - l + 1)个都等于val_mid,然后把实际上小于val_mid的减去
            }
        }
        int lpos=l;
        int rpos=mid+1;
        int same=0;
        for(int i=l;i<=r;i++){
            if(i==l){
                toLeft[d][i]=0;//toLeft[i]表示[ l , i ]区域里有多少个数分到左边
            }
            else{
                toLeft[d][i]=toLeft[d][i-1];
            }
            if(val[d][i]<sorted[mid]){
                toLeft[d][i]++;
                val[d+1][lpos++]=val[d][i];
            }
            else if(val[d][i]>sorted[mid]){
                val[d+1][rpos++]=val[d][i];
            }
            else{
                if(same<lsame){//有lsame的数是分到左边的
                    same++;
                    toLeft[d][i]++;
                    val[d+1][lpos++]=val[d][i];
                }
                else{
                    val[d+1][rpos++]=val[d][i];
                }
            }
        }
            build(d+1,lson);
            build(d+1,rson);
    }
    int query(int L,int R,int k,int d,int l,int r,int rt){
        if(l==r){
            return val[d][l];
        }
        int s;//s表示[ L , R ]有多少个分到左边
        int ss;//ss表示 [l , L-1 ]有多少个分到左边
        int mid=(l+r)>>1;
        if(L==l){
            s=toLeft[d][R];
            ss=0;
        }
        else{
            s=toLeft[d][R]-toLeft[d][L-1];
            ss=toLeft[d][L-1];
        }
        if(s>=k){//有多于k个分到左边,显然去左儿子区间找第k个
            int newl=l+ss;
            int newr=l+ss+s-1;//计算出新的映射区间
            return query(newl,newr,k,d+1,lson);
        }
        else {
            int bb=L-l-ss;//bb表示 [l , L-1 ]有多少个分到右边
            int b=R-L-s+1;//b表示 [L , R]有多少个分到右边
            int newl=mid+bb+1;
            int newr=mid+bb+b;
            return query(newl,newr,k-s,d+1,rson);
        }
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&val[0][i]);
            sorted[i]=val[0][i];
        }
        sort(sorted+1,sorted+n+1);
        build(0,1,n,1);
        while(m--){
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            printf("%d\n",query(l,r,k,0,1,n,1));
        }
        return 0;
    }
  • 相关阅读:
    jQuery Timer 实现的新邮件提醒
    在 jquery repeater 中添加设置日期,下拉,复选框等控件
    jquery repeater 完成 QQ 邮箱邮件分组显示功能
    Ajax 与 WebService 之间日期等数据类型的转换
    通过 Parameter 对象添加 Ajax 请求时的参数
    在 jQuery Repeater 进行验证更新等操作时提示消息
    jquery repeater 模仿 Google 展开页面预览子视图
    在 jQuery Repeater 中检索过滤数据
    功能完善的 jquery validator 完成用户注册的验证
    在 Repeater 中绑定转化 JSON 格式的字段
  • 原文地址:https://www.cnblogs.com/arbitrary/p/2637292.html
Copyright © 2011-2022 走看看