soj102 普通平衡树

题意:

标程:

 1 #include<cstdio>
 2 using namespace std;
 3 int read()
 4 {
 5     int x=0,f=1;char ch=getchar();
 6     while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
 7     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
 8     return x*f; 
 9 }
10 const int N=5000000;
11 int bit[N+2],op,x,n;
12 int lowbit(int x){return x&(-x);}
13 void add(int x,int y) {while (x<=N) bit[x]+=y,x+=lowbit(x);}
14 int sum(int x){int res=0;while (x) res+=bit[x],x-=lowbit(x);return res;}
15 int kth(int k)
16 {
17     if (!k||sum(N)<k) return -1;
18     int l=0,r;
19     for (int i=22;i>=0&&k;i--)
20       if ((r=l+(1<<i))<=N&&bit[r]<k) k-=bit[l=r]; 
21     return l+1;
22 }
23 int main()
24 {
25     n=read();
26     while (n--)
27     {
28         op=read(),x=read();
29         if (op==1) {if (!(sum(x)-sum(x-1))) add(x,1);}else
30         if (op==2) {if (sum(x)-sum(x-1)) add(x,-1);}else
31         if (op==3) printf("%d
",sum(x-1)+1);else
32         if (op==4) printf("%d
",kth(x));else
33         if (op==5) printf("%d
",kth(sum(x-1)));else
34         printf("%d
",kth(sum(x)+1));
35     }
36     return 0;
37 } 

易错点:1.注意5e6有2^22。

2.二分时先找到sum=k-1的最远处,然后+1,即是sum=k的第一点。

题解:树状数组+二分

由于这道题xi比较小,我们不用splay,直接用树状数组即可。

树状数组维护一个数值是否出现。

查询第k个直接在bit上二分即可,类似于倍增,因为树状数组上的每一段都是2的幂次,每一个数都是若干2的幂次的和。树状数组单点的话:除sum(x)-sum(x-1)外也可以用下面的方法:

int ans=bit[x];for (int i=x-1;i!=x-lowbit(x);i-=lowbit(i)) ans-=bit[i];因为在x-lowbit(x)的前面一段是互相抵消的,只需要计算最后一段lowbit的差即可。

原文地址:https://www.cnblogs.com/Scx117/p/8807335.html