题意:
标程:
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\n",sum(x-1)+1);else 32 if (op==4) printf("%d\n",kth(x));else 33 if (op==5) printf("%d\n",kth(sum(x-1)));else 34 printf("%d\n",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的差即可。