允许重复数字的划分树

const int MAXN = 50010,MAXM = 20;

int num[MAXN],tmp[MAXN],pre[MAXN];

int ans[MAXM][MAXN],val[MAXM][MAXN];

void Init(int l,int r,int h)
{
    if(l == r)
        return ;

    int mid = (l+r)>>1;

    int i,pl,pr,sum;

    for(i = l,pl = l,pr = mid+1,sum = 0;i <= r; ++i)
    {
        if(val[h][i] < tmp[mid] || (val[h][i] == tmp[mid] && sum < min(pre[mid],mid-l+1)))
        {
            val[h+1][pl++] = val[h][i],ans[h][i] = (i == l ? 1 : ans[h][i-1]+1) ;
            if(val[h][i] == tmp[mid])
                sum++;
        }
        else
            val[h+1][pr++] = val[h][i],ans[h][i] = (i == l ? 0 : ans[h][i-1]);
    }

    Init(l,mid,h+1);
    Init(mid+1,r,h+1);
}

int Query(int L,int R,int l,int r,int k,int h)
{
    if(L == R)
        return val[h][L];

    int goleftr = ans[h][r] ;//[L,r]内被分到左边的
    int goleftl = (l == L ? 0 : ans[h][l-1]);//[L,l-1]内被分到左边的
    int goleft = goleftr-goleftl;//[l,r]内被分到左边的
    int mid = (L+R)>>1;
    int gorightr = r-L+1 - ans[h][r];//[L,r]内被分到右边的
    int gorightl = l-L-goleftl;//[L,l-1]内被分到右边的

    if(k <= goleft)
        return Query(L,mid,L-1+goleftl+1,L-1+goleftr,k,h+1);
    return Query(mid+1,R,mid+gorightl+1,mid+gorightr,k-goleft,h+1);
}

void InitKthTree(int n)
{
        memcpy(tmp,num,sizeof(num));
        memcpy(val[0],num,sizeof(num));

        sort(tmp+1,tmp+n+1);
        int i;
        for(i = 2,pre[1] = 1;i <= n; ++i)
            pre[i] = (tmp[i] == tmp[i-1]  ?  pre[i-1]+1 : 1);

        Init(1,n,0);
}

时间: 2024-08-28 17:37:37

允许重复数字的划分树的相关文章

划分树基础知识

原网址:划分树详解 对4 5 2 8 7 6 1 3 分别建划分树和归并树 划分树如下图 红色的点是此节点中被划分到左子树的点. 我们一般用一个结构体数组来保存每个节点,和线段树不同的是,线段树每个节点值保存一段的起始位置和结束位置,而在划分树和递归树中,每个节点的每个元素都是要保存的.为了直观些,我们可以定义一个结构体数组,一个结构体中保存的是一层的元素和到某个节点进入左子树的元素的个数,不同于线段树,我们不能保存一个节点的起始结尾位置,因为随层数的增加,虽然每个结构体保存的元素数目是一定的,

[JLOI2011]不重复数字

2761: [JLOI2011]不重复数字 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2459  Solved: 939[Submit][Status][Discuss] Description 给出N个数,要求把其中重复的去掉,只保留第一次出现的数. 例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4. Input 输入第一行为正整数T,表示有T组数据. 接下来

POJ2104 K-th Number (子区间内第k大的数字)【划分树算法模板应用】

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 40920   Accepted: 13367 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

hdu 4417 Super Mario(离线树状数组|划分树)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2584    Accepted Submission(s): 1252 Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping a

poj 2401 划分树 求区间第k大的数

题目:http://poj.org/problem?id=2104 划分树待我好好理解下再写个教程吧,觉得网上的内容一般,,, 模板题: 贴代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define CLR(a) memset(a,0,sizeof(a)) const int MAXN = 1000

POJ 2104 划分树模板题

给出n,m n个数字 m次询问,每次询问(l,r)区间的第k小的数 划分树模板 mark一下 #include "stdio.h" #include "string.h" #include "algorithm" using namespace std; int a[100010],as[100010]; int tree[20][100010];// 记录第i层元素序列 int sum[20][100010];// 记录第i层的1~j划分到左子

划分树 静态第k大

划分树是保存了快速排序的过程的树,可以用来求静态第k小的数 如果,划分树可以看做是线段树,它的左孩子保存了mid-L+1 个 小于等于 a[mid] 的数字,  右孩子保存了 R-mid个大于等于a[mid]的数字 数组a是排序过后的数组,而划分树保存的是原数组的数据, 划分树的构造就是将上一层[l,r]个数的 mid-l+1个数划分到左子区间,r-(mid-l+1)个数划分到了右子区间 void build(int l, int r, int rt) { if (l == r) return;

划分树(poj2104)

poj2104 题意:给出n个数,有m次查询,每次查询要你找出 l 到 r 中第 k 大的数: 思路:划分树模板题 上述图片展现了查询时如何往下递推的过程 其中ly表示 [sl,l) 中有多少个数进入了左子树,num[ceng][r]表示[sl,r]中有多少个数进入了左子树,total表示[l,r]中有多少个数进入了左子树. 代码: #include<cstdio> #include<algorithm> using namespace std; int s[20][100010]

js选择颜色小游戏(随机生成不含重复数字的数组,通过数组中的数控制定义好的数组)

<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>js网页版小游戏</title> <style media="screen"> .wrap { width: 577px; outline: 1px solid hotpink; margin: 100px auto; box-shadow: 0 0 5px; } .