1. 程式人生 > >HDU2852 KiKi's K-Number (權值線段樹求第k大)

HDU2852 KiKi's K-Number (權值線段樹求第k大)

題意:三種操作,0 e 表示插入一個數字e,1 e 表示刪除一個數字e,2 e k 表示查詢比e大的第k個數,刪除和查詢均可能沒有
目標。

思路:建一棵權值線段樹,維護每個數字區間中數字的數量。 查詢時,先查出1到e的數字數量n,然後查詢第k+n大。
#include<cstdio>
#include<cstring>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 1e5 + 10;
const int
N = 100000; int num[maxn<<2]; void update(int pos,int val,int l,int r,int rt) { if(l==r) { if(num[rt]+val<0) { printf("No Elment!\n"); return ; } num[rt] += val; return ; } int m = l + r >> 1; if(pos<=m) update(pos,val,lson); else
update(pos,val,rson); num[rt] = num[rt<<1] + num[rt<<1|1]; } int query(int k,int l,int r,int rt)//找第k大 { if(num[rt]<k) { printf("Not Find!\n"); return -1; } if(l==r) return l; int m = l + r >> 1; if(k<=num[rt<<1
]) return query(k,lson); else return query(k-num[rt<<1],rson); } int query(int L,int R,int l,int r,int rt)//L<= <=R的數的數量 { if(L<=l&&r<=R) return num[rt]; int m = l + r >> 1; int ans = 0; if(L<=m) ans += query(L,R,lson); if(R>m) ans += query(L,R,rson); return ans; } void init() { memset(num,0,sizeof(num)); } int Q,p,e,k,n; int main() { while(scanf("%d",&Q)!=EOF) { init(); while(Q--) { scanf("%d%d",&p,&e); if(!p) update(e,1,1,N,1); else if(p==1) update(e,-1,1,N,1); else { scanf("%d",&k); n = query(1,e,1,N,1); k += n; n = query(k,1,N,1); if(n!=-1) printf("%d\n",n); } } } return 0; }