tyvj1728 普通平衡树

为了彻底理解树状数组,试着用树状数组做了下普通平衡树

而树状数组只能离线做,或者保证值的大小在数组可承受的范围内也是可以的,因为要求离线是因为必须事前对所有数离散化。

然后我们看刘汝佳蓝书上的图

利用如下代码,可以找到所有前缀和中第一个大于等于k的

1 int kth(int k) {
2     int ans=0;
3     for(int i=20;i>=0; --i) {
4         ans += 1<<i;
5         if(ans>=sz || C[ans]>=k) ans-=1<<i;
6         else k-=C[ans];
7     }
8     return seq[ans+1];
9 }        

什么原理呢,我们这么理解,把树状数组看成一棵树,事实上他的节点编号的中序遍历是有序的,跟平衡树有异曲同工之妙,假设现在在(1000)2这个点,如果往左走,就相当于没有取[1,8],接着在[1,7]中取,如果往右走,就相当于取了[1,8],接着在[9,15]中取,至于应该往左走还是往右走跟平衡树找第k大是一样的。然后可以发现,平衡树相当于是在[1,n]上建树的,而二叉索引树是在[1,2^k](k为2^k>=n的最小正整数)。

给出普通平衡树的完整代码

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<algorithm>
 6 
 7 using namespace std;
 8 
 9 const int Maxn=100010;
10 
11 int C[Maxn],sz;
12 
13 int sum(int x) {
14     int ret=0;
15     for(;0<x && x<=sz; x-=x&-x) ret+=C[x];
16     return ret;
17 }
18 
19 void add(int x,int d) {
20     for(;0<x&&x<=sz; x+= x&-x) C[x]+=d;
21 }
22 
23 int seq[Maxn],tot; 
24 void HashInit() {
25     sort(seq+1,seq+tot+1);
26     sz = unique (seq+1,seq+tot+1) - (seq+1);
27 }
28 int hash(int x) {
29     return lower_bound(seq+1,seq+sz+1,x) - seq;
30 }
31 
32 int opt[Maxn],num[Maxn];
33 
34 int kth(int k) {
35     int ans=0;
36     for(int i=20;i>=0; --i) {
37         ans += 1<<i;
38         if(ans>=sz || C[ans]>=k) ans-=1<<i;
39         else k-=C[ans];
40     }
41     return seq[ans+1];
42 }            
43 
44 int main() {
45 #ifdef DEBUG
46     freopen("in.txt","r",stdin);
47 //    freopen("out.txt","w",stdout);
48 #endif
49     
50     int n;
51     scanf("%d",&n);
52     for(int i=1;i<=n;i++) {
53         scanf("%d%d",opt+i,num+i);
54         if(opt[i]!=4) seq[++tot] = num[i];
55     }
56     
57     HashInit();
58     
59     for(int i=1;i<=n;i++) {
60         if(opt[i]==1) add(hash(num[i]),1);
61         if(opt[i]==2) add(hash(num[i]),-1);
62         if(opt[i]==3) printf("%d
",sum(hash(num[i])-1)+1);
63         if(opt[i]==4) printf("%d
",kth(num[i]));
64         if(opt[i]==5) printf("%d
",kth(sum(hash(num[i])-1)));
65         if(opt[i]==6) printf("%d
",kth(sum(hash(num[i]))+1));
66     }    
67     
68     return 0;
69 }
原文地址:https://www.cnblogs.com/showson/p/4665775.html