描述

传送门:POJ 2182 - Lost Cows

有一些奶牛,从 $1$ 到 $N$ 编号,现在这些奶牛站成一行,但是没有按顺序,我们只知道一个条件:
对于某一只奶牛,站在它前面并且编号比它小的奶牛的数量。
要求计算出每只奶牛的编号。

思路

根据题意,我们考虑最后一只奶牛(设为 $N$),我们知道站在它前面的并且编号比它小的奶牛的数目(设为 $Pre[N]$ ),因为所有的其他奶牛已经都在它前面了,所以 $Pre[N]$ 也就是所有奶牛中编号比它小的数目,那么这最后一只奶牛,编号就是 $Pre[N]+1$ 。

然后从后往前推,第 $N-1$ 只奶牛,站在它前面的编号比它小的奶牛数目是 $Pre[N-1]$ ,因为我们是从后往前推的,那么站在这第 $N-1$ 只奶牛后面的,编号肯定都已经确定了,那么从编号 $1$ 开始往后查找,第 $Pre[N-1]+1$ 个没有被确定的编号,就是它的编号。以此类推,直到所有奶牛的编号都确定下来。

因为题目数据范围较小,只有 $8000$, $O(n^2)$ 的暴力算法就可以过了,但是秉着学习的态度,还是用线段树解了一发,万一遇到数据很大的类似题目呢~!

代码 1 (暴力)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <cstdio>
#define MAX 8005
using namespace std;
int N, pre[MAX];
int Cows[MAX], sign[MAX];
int main(void)
{
scanf("%d", &N);
for (int i = 2; i <= N; ++i)
scanf("%d", &pre[i]);
Cows[N] = pre[N] + 1;
sign[pre[N] + 1] = 1;
for (int i = N - 1; i >= 1; --i)
{
int cnt = 0, j = 1;
while (cnt < pre[i] + 1)
if (sign[j++] == 0)
++cnt;
sign[j - 1] = 1;
Cows[i] = j - 1;
}
for (int i = 1; i <= N; ++i)
printf("%d\n", Cows[i]);
return 0;
}

代码 2 (线段树)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <cstdio>
#define MAX 8005
using namespace std;
struct node
{
int L, R;
int Cnt;
int Mid(void)
{
return (L + R) >> 1;
}
}Tree[MAX << 2];
void Build(int rt, int l, int r)
{
Tree[rt].L = l;
Tree[rt].R = r;
Tree[rt].Cnt = r - l + 1;
if (l != r)
{
Build(rt << 1, l, Tree[rt].Mid());
Build(rt << 1 | 1, Tree[rt].Mid() + 1, r);
}
}
void Modify(int rt, int i)
{
--Tree[rt].Cnt;
if (Tree[rt].L == Tree[rt].R)
return ;
if (Tree[rt].Mid() >= i)
Modify(rt << 1, i);
else
Modify(rt << 1 | 1, i);
}
int Query(int rt, int k)
{
if (Tree[rt].L == Tree[rt].R)
{
Modify(1, Tree[rt].L);
return Tree[rt].L;
}
if (Tree[rt << 1].Cnt >= k)
return Query(rt << 1, k);
else
return Query(rt << 1 | 1, k - Tree[rt << 1].Cnt);
}
int N, Pre[MAX], Cows[MAX];
int main(void)
{
scanf("%d", &N);
Build(1, 1, N);
for (int i = 2; i <= N; ++i)
scanf("%d", &Pre[i]);
Cows[N] = Pre[N] + 1;
Modify(1, Pre[N] + 1);
for (int i = N - 1; i >= 1; --i)
Cows[i] = Query(1, Pre[i] + 1);
for (int i = 1; i <= N; ++i)
printf("%d\n", Cows[i]);
return 0;
}