【题解】CF91B
题目大意:
-
给定 \(n\) 个正整数 。
-
对于每一个数 \(a_i\),需要输出一个答案:
- 设 \(a_j > a_i\) 且 \(j > i\);
- 在满足第一条的基础上使 \(j-i-1\) 尽可能大,此时 \(j-i-1\) 即为答案。
- 若没有找到 \(j\) 使得 \(a_j > a_i\) 且 \(j > i\),输出 \(-1\)。
本题思路
由 \(a_j > a_i\) 且 \(j > i\) 可以想到逆序对,既然刚学了值域线段树,那就用值域线段树吧。
但注意数据范围:\(a_i \le 10^9\),直接开数组会爆,故需离散化一下。
离散化很简单,举个例子:
\(1\quad-100\quad5\quad-10^9\)
离散化大概就是:如果一个数 \(i\) 是数组中第 \(j\) 大(或小)的,那么就用 \(j\) 来代替 \(i\)。
上面的数组离散化就变成了(从大到小)
\(2\quad3\quad1\quad4\)
本题另一个需要注意的地方是:答案求的是最大值,所以线段树保存的是最大值。
\(\color{black}\texttt{AC}\) \(\color{black}\texttt{CODE}\)
#include <iostream>
#include <cstdio>
#include <algorithm>
#define lpos pos << 1
#define rpos pos << 1 | 1
using namespace std;
const int MAXN = 1e5 + 5;
int n;
int ans[MAXN];
struct num
{
int val, id;
bool operator <(const num &x)const
{
if (x.val == val)
{
return x.id > id;
}
return x.val > val;
}
}a[MAXN];
struct tree
{
int l, r, val;
}t[MAXN << 2];
void pushup(int pos)
{
t[pos].val = max(t[lpos].val, t[rpos].val);
}
inline void build(int pos, int l, int r)
{
t[pos].l = l, t[pos].r = r;
if (l == r)
{
return;
}
int mid = (l + r) >> 1;
build(lpos, l, mid);
build(rpos, mid + 1, r);
}
inline void update(int pos, int dis)
{
int l = t[pos].l, r = t[pos].r;
if (l == r)
{
t[pos].val = dis;
return;
}
int mid = (l + r) >> 1;
if (dis <= mid)
{
update(lpos, dis);
}
else
{
update(rpos, dis);
}
pushup(pos);
}
inline int query(int pos, int L, int R)
{
int l = t[pos].l, r = t[pos].r;
if (l >= L && r <= R)
{
return t[pos].val;
}
int mid = (l + r) >> 1, res = -1;
if (L <= mid)
{
res = query(lpos, L, R);
}
if (R > mid)
{
res = max(res, query(rpos, L, R));
}
return res;
}
int main()
{
scanf("%d", &n);
build(1, 1, n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i].val);
a[i].id = i;
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++)
{
int id = a[i].id;
update(1, id);
int res = query(1, 1, n);
if (res >= 0)
{
ans[id] = res - id - 1;
}
else
{
ans[id] = -1;
}
}
for (int i = 1; i <= n; i++)
{
printf("%d ", ans[i]);
}
return 0;
}