1 int find_kth(int k) 2 { 3 int ans = 0, cnt = 0, i; 4 for (i = 20; i >= 0; i--)/ 5 { 6 ans += (1 << i); 7 if (ans >= maxn|| cnt + c[ans] >= k) 8 ans -= (1 << i); 9 else 10 cnt += c[ans]; 11 } 12 return ans + 1; 13 }
题意:
口袋里可以放进不同大小的糖果,也可以拿出不同大小的糖果。查询过程中第k小的糖果体积是多少
输入T,有T组,接下来是输入m次操作
m行输入op和x
当op等于1的时候,放进x大小的糖果
当op等于2的时候,拿进x大小的糖果
当op等于3的时候,查询第x小的糖果,并输出答案
思路:二分+树状数组(比赛时限)
这里写一个优化的树状数组的写法
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<string> #define mem(a,b) memset(a,b,sizeof(a)) #define inf 0x3f3f3f3f #define ll long long #define lowbit(b) b&(-b) using namespace std; const int maxn=1e5+10; int c[maxn],f[20]; inline int read() { char ch = getchar(); int x = 0, f = 1; while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); } while('0' <= ch && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } inline void updata(int x, int y){ for (int i = x; i <= maxn; i += lowbit(i)){ c[i] += y; } } int main() { int t,i;f[0]=1; for(i=1;i<=17;i++){ f[i]=f[i-1]*2; } t=read(); while(t--){ for(i=0;i<maxn;i++){c[i]=0;} int m; m=read(); for(i=0;i<m;i++){ int op,x; op=read();x=read(); if(op==1){ updata(x,1); } else if(op==2){ updata(x,-1); } else{ int ans=0,sum=0,j; for(j=17;j>=0;j--){ ans+=f[j]; if(ans>=maxn || sum+c[ans]>=x){ ans-=f[j]; } else{ sum+=c[ans]; } } printf("%d ",ans+1); } } } return 0; } /* 2 3 1 2 1 2 3 1 4 1 2 1 3 2 2 3 1 */
顺便放一下逆序数的板子
#define N 1010 int c[N]; int n; int lowbit(int i) { return i&(-i); } void insert(int i,int x) { while(i<=n){ c[i]+=x; i+=lowbit(i); } } int getsum(int i) { int sum=0; while(i>0){ sum+=c[i]; i-=lowbit(i); } return sum; } void output() { for(int i=1;i<=n;i++) cout<<c[i]<<" "; cout<<endl; } int main() { while(cin>>n){ int ans=0; memset(c,0,sizeof(c)); for(int i=1;i<=n;i++){ int a; cin>>a; insert(a,1); ans+=i-getsum(a);//统计当前序列中大于a的元素的个数 } cout<<ans<<endl; } return 0; }