HDU - 2852 KiKi's K-Number(树状数组+二分)
题意:
给定一个容器,该容器支持的操作有三种:
1、加入一个元素
2、删除一个元素
3、查询 $k th$ 比 $a$ 大的数
思路:
元素的值在1e5之内,可以直接用树状数组记录出现的次数
查询的时候用二分查找第k大的数。
1 /* 2 * Author: windystreet 3 * Date : 2018-08-10 09:05:15 4 * Motto : Think twice, code once. 5 */ 6 #include<bits/stdc++.h> 7 8 using namespace std; 9 10 #define X first 11 #define Y second 12 #define eps 1e-5 13 #define gcd __gcd 14 #define pb push_back 15 #define PI acos(-1.0) 16 #define lowbit(x) (x)&(-x) 17 #define bug printf("!!!!!\n"); 18 #define mem(x,y) memset(x,y,sizeof(x)) 19 20 typedef long long LL; 21 typedef long double LD; 22 typedef pair<int,int> pii; 23 typedef unsigned long long uLL; 24 25 const int maxn = 1e5+7; 26 const int INF = 1<<30; 27 const int mod = 1e9+7; 28 29 int tree[maxn]; 30 int n,sum; 31 void init(){ 32 for(int i=0;i<maxn;i++) 33 tree[i] = 0; 34 } 35 void add(int x,int v){ 36 for(int i=x;i<maxn;i+=lowbit(i)) 37 tree[i]+=v; 38 } 39 int query(int x){ 40 int res = 0; 41 for(int i=x;i;i-=lowbit(i)) 42 res += tree[i]; 43 return res; 44 } 45 bool check(int x,int y){ 46 int k = query(x) - sum; 47 return k>=y; // 若当前值 >=y 则记录答案 48 } 49 50 void solve(){ 51 int m,op,x,y; 52 while(~scanf("%d",&m)){ 53 init(); // 多case不忘初始化 54 while(m--){ 55 scanf("%d",&op); 56 if(op==0){ 57 scanf("%d",&x); 58 add(x,1); 59 }else if(op==1){ 60 scanf("%d",&x); 61 if(query(x)-query(x-1)){ 62 add(x,-1); 63 }else{ 64 puts("No Elment!"); // 若当前值不存在 65 } 66 }else{ 67 scanf("%d%d",&x,&y); 68 sum = query(x); // 记录 [1,x] 区间内元素的个数 69 int L = x, R = maxn-1,ans = -1,mid; 70 while(L<=R){ 71 mid = (L + R)>>1; 72 if(check(mid,y)) ans = mid, R = mid-1; 73 else L = mid+1; 74 } 75 if(ans==-1){ 76 puts("Not Find!"); 77 }else{ 78 printf("%d\n",ans); 79 } 80 } 81 } 82 } 83 return; 84 } 85 86 int main() 87 { 88 // freopen("in.txt","r",stdin); 89 // freopen("out.txt","w",stdout); 90 // ios::sync_with_stdio(false); 91 int t = 1; 92 //scanf("%d",&t); 93 while(t--){ 94 // printf("Case %d: ",cas++); 95 solve(); 96 } 97 return 0; 98 }