您的位置:首页 > 其它

hdu 2852 KiKi's K-Number (线段树,求大于x的第k小数)

2012-08-26 13:07 676 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: