poj 2828(线段树)

//题目的关键就在于查询元素所在的位置
int query(int l,int r,int rt,int p)
{
    if(l==r)
    {
        sum[rt]=0;
        return l;
    }
    int ret;
    int m=(l+r)>>1;
    if(p<sum[rt<<1])  //与2182 相类似,不过这里只有<  不是<=。要好好想清楚,在这道题目中,你从后往前插,p若是与sum[rt<<1] 相同,说明最开始排队是 p先占了这个位置,后来p被人插队,p必定会往后移动一个位置。所以只能是<  。表达得可能不是很明白,但要仔细想想就懂了
        ret=query(l,m,rt<<1,p);
    else
        ret=query(m+1,r,rt<<1|1,p-sum[rt<<1]);
    push_up(rt);
    return ret;
}

这道题目与poj 2182 相类似,不过在这道题目中pos[i] =2就表明 该元素在0—n-1 的中的2 的位置。 在2182中的pos 表示他前面有多少只牛,要自加一再来从查询。

这张图片是我的插入过程。
第一次插 2 69
2 不可能小于sum[rt<<1]=2 所以往右边走到2-3
query(rson, 2-sum[rt<<1]) 即query(rson,0);
轻易的就能得到第一个答案。
在2处放69

更新区间。

接着找1 33
由于1< 2 成立,走到0-1;
后来1不可能小于1 ,于是走到了 1. 这里就放33.

更新区间

再找1 51
这是1 不小于1 于是走到了2-3;
query( rson ,1-0) 最后达到3 ,插入51.

最后以此类推在0 处插入77

贴上完整代码
要注意区间的下标0- n-1

#include <stdio.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define N 200005
int sum[N<<2];
int val[N];
int pos[N];
int result[N];
void push_up(int rt)
{  sum[rt]=sum[rt<<1]+sum[rt<<1|1];  }
void build(int l,int r,int rt)
{  if(l==r)
   {  sum[rt]=1;
      return ;
   }
   int m=(l+r)>>1;
   build(lson);
   build(rson);
   push_up(rt);
}
int query(int l,int r,int rt,int p)
{  if(l==r)
   {  sum[rt]=0;
      return l;
   }
   int m=(l+r)>>1;
   int ret;
   if(p<sum[rt<<1])
      ret=query(lson,p);
   else 
      ret=query(rson,p-sum[rt<<1] );
   push_up(rt);
   return ret;
}
int main()
{  int n,i;
   while(scanf("%d",&n)!=EOF)
   {
       build(0,n-1,1);
       for(i=0;i<n;i++)
          scanf("%d%d",&pos[i],&val[i] );
       for(i=n-1;i>=0;i--)
          result[ query(0,n-1,1,pos[i] ) ]=val[i];
       for(i=0;i<n-1;i++)
          printf("%d ",result[i]);
       printf("%d\n",result[i]);
   }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值