poj2182 Lost Cows (线段树)

传送门
大意:有一个1-n的排列,数据给出从第二个到第n个数中的每一个数前面有几个数比这个数小,要求还原这个1-n的排列
思路:最近做这种题好像有点感觉了,很自然的想到,我们可以从最后一个数来倒推,一直推出第一个过后就可以完事了。这样的话,我们很容易写出一个 N² 的算法。但作为一名OIer,我们要求上进,所以我们就会想,可不可以优化一下呢。其实我们发现,在找前面出现了几个比目标值小的操作很冗余,我们可以考虑用线段树来优化。那么我们就可以在 O(NlogN) 的时间内求出来整个序列

代码:

#include<cstdio>
#define MAXN 8005
struct node
{
    int l, r, len;
}t[MAXN * 4];
void Build(int i, int l, int r)
{
    t[i].l = l, t[i].r = r;
    t[i].len = r-l+1;
    if(l == r) return;
    int mid = (l + r) >> 1;
    Build(i<<1, l, mid);
    Build(i<<1|1, mid + 1, r);
}
int Q(int i, int num)
{
    -- t[i].len;
    if(t[i].l == t[i].r) return t[i].l;
    if(num > t[i<<1].len) return Q(i<<1|1, num - t[i<<1].len);
    else return Q(i<<1, num);
}
int n, a[MAXN], ans[MAXN];
int main()
{
    scanf("%d", &n);
    Build(1, 1, n);
    for(int i = 2; i <= n; i ++)
        scanf("%d", &a[i]);
    for(int i = n; i > 0; i --)
        ans[i] = Q(1, a[i] + 1);
    for(int i = 1; i <= n; i ++)
        printf("%d\n", ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值