【模板】划分树

K-th Number

多次询问一个静态区间里的第k大数。怎么搞?

暴力?(还是别想了)

多次构建树状数组?(和暴力有啥区别)

于是一个叫做划分树的东西就登场了。(据说还有个叫归并树的,速度慢一点,就不学了)

划分树详解

——代码

 1 #include <cstdio>
 2 #include <algorithm>
 3 #define N 100001
 4
 5 using namespace std;
 6
 7 int n, m;
 8 int c[N];//排序后数组
 9 int num[20][N], val[20][N];
10 //一共有20层,每一层元素排放,0层是原数组
11 //num[i] 表示 i 前面有多少个孩子进入左孩子
12
13 inline void build(int l, int r, int k)
14 {
15     if(l == r) return;
16     int i, mid = (l + r) / 2, lc = l, rc = mid + 1, isame = mid - l + 1;
17     //isame 表示有多少个和 c[mid] 相同的数进入左边,先假设全部进入左边
18     for(i = l; i <= r; i++)
19      if(val[k][i] < c[mid])
20       isame--;//判断,把进入左边的且小于 c[mid] 的减去
21     for(i = l; i <= r; i++)
22     {
23         num[k][i] = i == l ? 0 : num[k][i - 1];//dp
24         if(val[k][i] < c[mid] || (val[k][i] == c[mid] && isame > 0))//进入左孩子
25         {
26             val[k + 1][lc++] = val[k][i];
27             num[k][i]++;
28             if(val[k][i] == c[mid]) isame--;
29         }
30         else val[k + 1][rc++] = val[k][i];//到右孩子
31     }
32     build(l, mid, k + 1);
33     build(mid + 1, r, k + 1);
34 }
35
36 inline int query(int l, int r, int k, int ql, int qr, int qk)
37 {
38     if(l == r) return val[k][l];//叶子节点即为结果
39     int lnum = l == ql ? 0 : num[k][ql - 1], t = num[k][qr] - lnum, mid = (l + r) / 2;//左端点相同?
40     //lnum 表示 ql 前面有多少个数进入左孩子,t 表示 ql 和 qr 之间有多少个数进入左孩子
41     if(t >= qk) return query(l, mid, k + 1, l + lnum, l + num[k][qr] - 1, qk);
42     //全在左子树,去左子树搜索
43     else
44     {
45         //ql - l 表示 ql 前面有多少个数,再减去 lnum 表示有多少个数去了右子树
46         int kj = mid + 1 + (ql - l - lnum);
47         //ql - qr + 1 表示 ql 到 qr 有多少数,减去左边的,剩下的就是去右边的,去右边一个,下标就是kj,所以减一
48         return query(mid + 1, r, k + 1, kj, kj + qr - ql + 1 - t - 1, qk - t);
49     }
50 }
51
52 int main()
53 {
54     int i, x, y, z;
55     while(~scanf("%d %d", &n, &m))
56     {
57         for(i = 1; i <= n; i++) scanf("%d", &val[0][i]), c[i] = val[0][i];
58         sort(c + 1, c + n + 1);
59         build(1, n, 0);
60         for(i = 1; i <= m; i++)
61         {
62             scanf("%d %d %d", &x, &y, &z);
63             printf("%d\n", query(1, n, 0, x, y, z));
64         }
65     }
66     return 0;
67 }

当然还有其他方法,不过代码量都比较大。

可以看看这篇blog

时间: 2024-10-12 19:55:12

【模板】划分树的相关文章

poj 2104 K-th Number(划分树模板)

划分树模板题,敲上模板就ok了. #include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #define MP

POJ--2104--K-th Number【划分树模板】

链接:http://poj.org/problem?id=2104 题意:给一个n个元素的数组,m次询问,每次查询区间[i,j]中第k大的数,输出这个数. 思路:划分树模板题 划分树讲解:传送门 我用的是kuangbin大神的模板 #include<cstring> #include<string> #include<fstream> #include<iostream> #include<iomanip> #include<cstdio&

划分树模板

1 ///划分树模板,找区间第k小的数 2 const int mx=1e5+5; 3 int tree[30][mx]; 4 int sortt[mx]; 5 int sum[30][mx]; 6 7 void build(int l,int r,int c) 8 { 9 if (l==r) return ; 10 int m=(l+r)>>1; 11 int isame=m-l+1; 12 int pl=l,pr=m+1; 13 for (int i=l;i<m;i++) 14 if

划分树模板题

原题http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 37130   Accepted: 11974 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing

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划分到左子

划分树 模板

#include <iostream> #include <cstdio> #include <algorithm> using namespace std; #define N 100500 #define MID ((l+r)>>1) int a[N],s[N],t[20][N],num[20][N],n,m; // void build(int lft,int rht,int ind) // { // if(lft==rht) return; // /

poj 2104 划分树模板

划分树的模板题. 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 100001; 7 int tree[20][N]; 8 int sum[20][N]; 9 int as[N]; 10 11 void build( int p, int l, int r ) 12 { 13 int mid = ( ( l

划分树模板+模板题--hdu4251

题目链接:点击进入 划分树解决的是快速求区间中第k大值的问题,算法的主要思想是基于线段树和快排的划分方法,可以实现在logn时间内求出任意区间的第k大值.下面这份代码是基于hud4251的一份模板. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100000+1000; in

HDU 3473 Minimum Sum 划分树,数据结构 难度:1

http://acm.hdu.edu.cn/showproblem.php?pid=3473 划分树模板题目,需要注意的是划分树的k是由1开始的 划分树: 参考:http://blog.csdn.net/shiqi_614/article/details/8041390 划分树的定义 划分树定义为,它的每一个节点保存区间[lft,rht]所有元素,元素顺序与原数组(输入)相同,但是,两个子树的元素为该节点所有元素排序后(rht-lft+1)/2个进入左子树,其余的到右子树,同时维护一个num域,