zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 344 反转字符串
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
  • 原文地址:https://www.cnblogs.com/showson/p/4665775.html
Copyright © 2011-2022 走看看