const int MAXL(1e5);
int tree[20][MAXL+50];//第一維表明當前的樹的層數,
//第二維表明這一層通過劃分後的序列值
int toLeft[20][MAXL+50];//第一維表明當前的樹的層數,
//第二維表明當前層區間[left,right]進入左子樹的數目
int sorted[MAXL+50];//將初始序列排序後的數組
按照圖中給出的原始序列爲.net
1
4 2 5 7 1 8 3 6
排序後的序列爲code
1
1 2 3 4 5 6 7 8
那麼咱們tree [ 0 ]保存的應該是原始序列 而且獲得toLeft [ 0 ] 的序列
1
2
3
tree[0] = 42571836toLeft[0]= 12223344
再次強調一遍 toLeft [ i ] [ j ] 存的是 第 i 層,當前劃分區間【 left , right 】裏進入左子樹的個數 至於爲何要這麼存,一會說查詢的時候就知道了。
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<cmath>#include<iomanip>#include<map>#include<stack>#include<vector>#include<queue>#include<set>#include<utility>#include<list>#include<algorithm>#define max(a,b) (a>b?a:b)#define min(a,b) (a<b?a:b)#define swap(a,b) (a=a+b,b=a-b,a=a-b)#define memset(a,v) memset(a,v,sizeof(a))#define X (sqrt(5)+1)/2.0 //Wythoff#define Pi acos(-1)#define e 2.718281828459045#define eps 1.0e-8usingnamespacestd;
typedeflonglongint LL;
typedef pair<int,int>pa;
constint MAXL(1e5);
constint INF(0x3f3f3f3f);
constint mod(1e9+7);
int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
int tree[20][MAXL+50];
int toLeft[20][MAXL+50];
int sorted[MAXL+50];
void Build_tree(int level,int left,int right)
{
if(left==right)
return ;
int mid=(left+right)>>1;
int suppose=mid-left+1;
for(int i=left; i<=right; i++)
if(tree[level][i]<sorted[mid])
suppose--;
int subLeft=left,subRight=mid+1;
for(int i=left; i<=right; i++)
{
if(i==left)
toLeft[level][i]=0;
else
toLeft[level][i]=toLeft[level][i-1];
if(tree[level][i]<sorted[mid]||tree[level][i]==sorted[mid]&&suppose>0)
{
tree[level+1][subLeft++]=tree[level][i];
toLeft[level][i]++;
if(tree[level][i]==sorted[mid])
suppose--;
}
else
tree[level+1][subRight++]=tree[level][i];
}
Build_tree(level+1,left,mid);
Build_tree(level+1,mid+1,right);
}
int Query(int level,int qLeft,int qRight,int left,int right,int k)
{
int mid=(left+right)>>1;
if(qLeft==qRight)
return tree[level][qLeft];
int lef;
int toLef;
if(qLeft==left)
lef=0,toLef=toLeft[level][qRight];
else
lef=toLeft[level][qLeft-1],toLef=toLeft[level][qRight]-lef;
if(k<=toLef)
{
int newLeft=left+lef;
int newRight=left+lef+toLef-1;
return Query(level+1,newLeft,newRight,left,mid,k);
}
else
{
int newLeft=mid+qLeft-left-lef+1;
int newRight=mid+qRight-left-toLef-lef+1;
return Query(level+1,newLeft,newRight,mid+1,right,k-toLef);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
scanf("%d",&tree[0][i]);
sorted[i]=tree[0][i];
}
sort(sorted+1,sorted+n+1);
Build_tree(0,1,n);
while(m--)
{
int ql,qr,k;
scanf("%d%d%d",&ql,&qr,&k);
int ans=Query(0,ql,qr,1,n,k);
cout<<ans<<endl;
}
}
作題的過程當中發現了toLeft數組的另外一種存法
下面的模板代碼對於toLeft【i】【j】存的是第 i 層 1到 j 進入左子樹的元素個數 copy下別人的模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>usingnamespacestd;
#define MAX_SIZE 100005 int sorted[MAX_SIZE];//已經排好序的數據 int toleft[25][MAX_SIZE];
int tree[25][MAX_SIZE];
void build_tree(int left, int right, int deep)
{
int i;
if (left == right) return ;
int mid = (left + right) >> 1;
int same = mid - left + 1; //位於左子樹的數據 for (i = left; i <= right; ++i) {//計算放於左子樹中與中位數相等的數字個數 if (tree[deep][i] < sorted[mid]) {
--same;
}
}
int ls = left;
int rs = mid + 1;
for (i = left; i <= right; ++i) {
int flag = 0;
if ((tree[deep][i] < sorted[mid]) || (tree[deep][i] == sorted[mid] && same > 0)) {
flag = 1;
tree[deep + 1][ls++] = tree[deep][i];
if (tree[deep][i] == sorted[mid])
same--;
} else {
tree[deep + 1][rs++] = tree[deep][i];
}
toleft[deep][i] = toleft[deep][i - 1]+flag;
}
build_tree(left, mid, deep + 1);
build_tree(mid + 1, right, deep + 1);
}
int query(int left, int right, int k, int L, int R, int deep)
{
if (left == right)
return tree[deep][left];
int mid = (L + R) >> 1;
int x = toleft[deep][left - 1] - toleft[deep][L - 1];//位於left左邊的放於左子樹中的數字個數 int y = toleft[deep][right] - toleft[deep][L - 1];//到right爲止位於左子樹的個數 int ry = right - L - y;//到right右邊爲止位於右子樹的數字個數 int cnt = y - x;//[left,right]區間內放到左子樹中的個數 int rx = left - L - x;//left左邊放在右子樹中的數字個數 if (cnt >= k) {
//printf("sss %d %d %d\n", xx++, x, y); return query(L + x, L + y - 1, k, L, mid, deep + 1);
// 由於x不在區間內 因此不要緊 因此先除去,從L+x開始,而後肯定範圍
}
else {
//printf("qqq %d %d %d\n", xx++, x, y); return query(mid + rx + 1, mid + 1 + ry, k - cnt, mid + 1, R, deep + 1);
//同理 把不在區間內的 分到右子樹的元素數目排除,肯定範圍
}
}
int main()
{
int m, n;
int a, b, k;
int i;
while (scanf("%d%d", &m, &n) == 2) {
for (i = 1; i <= m; ++i) {
scanf("%d", &sorted[i]);
tree[0][i] = sorted[i];
}
sort(sorted + 1, sorted + 1 + m);
build_tree(1, m, 0);
for (i = 0; i < n; ++i) {
scanf("%d%d%d", &a, &b, &k);
printf("%d\n", query(a, b, k, 1, m, 0));
}
}
return0;
}