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

    划分树:一般用于快速求区间[a,b]第k大的数。

    /****************-划分树模板-*****************/
    //建树nlog(n) 查询log(n) 其实就是一种特殊形式的线段树
    //使用方法参见main.
    //isum表示区间内第[1,2,...k-1]的所有所有数之和(使用前先赋0)
    
    #define MID(a,b) (a+((b-a)>>1))
    typedef long long LL;
    const int N=1e5+5;
    struct P_Tree
    {
        int n,order[N];
        int valu[20][N],num[20][N];
        LL sum[N],lsum[20][N],isum;
        void init(int len)
        {
            n=len;  sum[0]=0;
            for(int i=0;i<20;i++) valu[i][0]=0,num[i][0]=0,lsum[i][0]=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&order[i]);
                valu[0][i]=order[i];
                sum[i]=sum[i-1]+order[i];
            }
            sort(order+1,order+1+n);
            build(1,n,0);
        }
        void build(int lft,int rht,int ind)
        {
            if(lft==rht) return;
            
            int mid=MID(lft,rht);
            int same=mid-lft+1,ln=lft,rn=mid+1;
            for(int i=lft;i<=rht;i++)
                if(valu[ind][i]<order[mid]) same--;
            for(int i=lft;i<=rht;i++)
            {
                int flag=0;
                if((valu[ind][i]<order[mid])||(valu[ind][i]==order[mid]&&same))
                {
                    flag=1;
                    valu[ind+1][ln++]=valu[ind][i];
                    lsum[ind][i]=lsum[ind][i-1]+valu[ind][i];
                    if(valu[ind][i]==order[mid]) same--;
                }
                else
                {
                    valu[ind+1][rn++]=valu[ind][i];
                    lsum[ind][i]=lsum[ind][i-1];
                }
                num[ind][i]=num[ind][i-1]+flag;
            }
            build(lft,mid,ind+1);
            build(mid+1,rht,ind+1);
        }
        int query(int st,int ed,int k,int lft,int rht,int ind)
        {
            if(lft==rht) return valu[ind][lft];
            
            int mid=MID(lft,rht);
            int lx=num[ind][st-1]-num[ind][lft-1];//lx表示从lft到st-1这段区间内有多少个数进入左子树
            int ly=num[ind][ed]-num[ind][st-1];//ly表示从st到ed这段区间内有多少个数进入左子树
            int rx=st-1-lft+1-lx;//rx表示从lft到st-1这段区间内有多少个数进入右子树
            int ry=ed-st+1-ly;//ry表示从st到ed这段区间内有多少个数进入右子树
            if(ly>=k) return query(lft+lx,lft+lx+ly-1,k,lft,mid,ind+1);
            else
            {
                isum+=lsum[ind][ed]-lsum[ind][st-1];
                st=mid+1+rx;
                ed=mid+1+rx+ry-1;
                return query(st,ed,k-ly,mid+1,rht,ind+1);
            }
        }
    }tree;
    
    //int main()
    //{
    //    int n,m;
    //    while(scanf("%d%d",&n,&m)!=EOF)
    //    {
    //        tree.init(n);
    //        for(int i=0;i<m;i++)
    //        {
    //            int a,b,c;
    //            scanf("%d%d%d",&a,&b,&c);
    //            int res=tree.query(a,b,c,1,n,0);
    //            printf("%d
    ",res);
    //        }
    //    }
    //    return 0;
    //}
  • 相关阅读:
    【原创】禁止快播自动升级到最新版本,自己发现的方法
    又一灵异事件 Delphi 2007 在 Win7
    [DCC Error] E2161 Error: RLINK32: Error opening file "_____.drf"
    单例模式 改进
    estackoverflow with message 'stack overflow'
    所有可选的快捷键列表[转自万一博客]
    SQL server 除法运算
    正则表达式的一个坑[.\n]无效引起的血案
    getcwd()和__DIR__区别
    并发处理的技巧php
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5756075.html
Copyright © 2011-2022 走看看