http://acm.hdu.edu.cn/showproblem.php?pid=2852
(1)求比x大的第k个最小值。问题可以分解为两个子问题:
1)求不大于x 的数的个数t。(本质为求和)
2)求树里头的第t+y个数的值。(本质为定位)
(2)考虑过直接计算出结果:
search(y, x, n, 1);
即在区间(x, n)中寻找第y个数。
这种思想是可行的,但不适合已经构建的这棵树。因为已有的线段树只能从区间(1, 某数)开始查询,区间(x, n)与sum[]数组的描述方式对不上号。
(原有的sum[]数组中可能不含描述区间(x, n)的sum[i],并且一般情况下就是不包含对该区间的该描述)。
正确的分段式处理如下:
x=add(1, x, 1, n, 1); y+=x; query(y, 1, n, 1);
具体代码:
View Code
#include<stdio.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 const int maxn=101000; int n=maxn, m; int sum[maxn<<2]; void pushup(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l, int r, int rt) { sum[rt]=0; if(l==r) { return ; } int m=l+r>>1; build(lson); build(rson); } void inserts(int val, int l, int r, int rt) { if(l==r) { sum[rt]++; return ; } int m=l+r>>1; if(val<=m) inserts(val, lson); else inserts(val, rson); pushup(rt); } void deletes(int val, int l, int r, int rt) { if(l==r) { if(sum[rt]==0) printf("No Elment!\n"); else sum[rt]--; return ; } int m=l+r>>1; if(val<=m) deletes(val, lson); else deletes(val, rson); pushup(rt); } int add(int L, int R, int l, int r, int rt) { if(L<=l&&r<=R) { return sum[rt]; } int m=l+r>>1; int ret=0; if(L<=m) ret+=add(L, R, lson); if(R>m) ret+=add(L, R, rson); return ret; } void query(int p, int l, int r, int rt) { if(l==r) { printf("%d\n", l); return ; } int m=l+r>>1; if(p<=sum[rt<<1]) query(p, lson); else query(p-sum[rt<<1], rson); } int main() { while(scanf("%d", &m)!=EOF) { build(1, n, 1); for(int i=1;i<=m;i++) { int a, x, y; scanf("%d", &a); if(a==0) { scanf("%d", &x); inserts(x, 1, n, 1); } else if(a==1) { scanf("%d", &x); deletes(x, 1, n, 1); } else { scanf("%d%d", &x, &y); x=add(1, x, 1, n, 1); y+=x; if(y>sum[1]) printf("Not Find!\n"); else query(y, 1, n, 1); } } } return 0; }