POJ 2182 线段树最佳

又一次对自己的智商产生了怀疑。。这道题虽然用N方的循环也能水过但是刚学过线段树还是自己用线段树做一遍吧~~
看着题解做的。。因为实在想不到线段树该怎么处理。。
等我学完专题一定发誓从此不再看题解。。嘤嘤。。被自己蠢哭了。。。


题目大意:一群有编号的牛乱序排成一列,已知每头牛之前的编号小于自己的牛的个数,要求按顺序输出这列牛的编号。。
思路:使用一个线段树维护全部牛编号的排序,可以求出当前第K大的编号,node中的len属性是计数自己下属剩余编号的个数,每查询一次自减一次,叶子节点len==0表示已被使用,由于查询子树时会与子树剩余结点数相比较,并且查询右子树时会用K减去左子树的剩余结点数,所以len=0相当于节点被删除。巧妙高效的实现了删除操作。


#include<stdio.h>
#include<iostream>
#include<math.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define MAX_N 8005
struct node
{
    int l;
    int r;
    int len;
}tree[MAX_N<<2];             //tree的第0位不使用
int source[MAX_N];
int ans[MAX_N];
void build(int l,int r,int dex)
{
    tree[dex].l=l;
    tree[dex].r=r;
    tree[dex].len=r-l+1;
    if(l==r)  return;
    build(l,(l+r)/2,dex<<1);
    build((l+r)/2+1,r,(dex<<1)+1);
    return;
}
int query(int dex,int sum)
{
    tree[dex].len--;          //当len==0时,相当于该节点被删除
    if(tree[dex].l==tree[dex].r)
        return tree[dex].l;
    if(sum<=tree[dex<<1].len)   //与左子树剩余结点数相比较
        return query(dex<<1,sum);
    if(sum>tree[dex<<1].len)
        return query((dex<<1)+1,sum-tree[dex<<1].len);

}
int main()
{
    int n;
    scanf("%d",&n);
    source[1]=0;
    for(int i=2;i<=n;i++)
        scanf("%d",&source[i]);
    build(1,n,1);
    for(int i=n;i>=1;i--)
        ans[i]=query(1,source[i]+1);
    for(int i=1;i<=n;i++)
        printf("%d\n",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值