2019ICPC徐州网络赛 E 线段树 + 二分

竟然是线段树?

队友二分过的,tql

链接

题意+

让你求大于这个数+m的最远的那个数与当前数字的中间有几个数字。

思路

我们先将这个序列排序,并记录每个数字的位置。然后我们遍历每个数字的时候: 首先找到大于当前数字的排好序的序列中的位置,查询这个位置到最后位置的区间中坐标的最大值。这个查询就是线段树,我们需要事先建好以排好序的序列中的元素的下标为叶子节点的线段树。

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <bits/stdc++.h>

using namespace std;
const int maxn = 500005;

struct node{
int value,pos;
}a[maxn];
int b[maxn],c[maxn],ans[maxn],d[maxn];
int tr[maxn << 2];
bool cmp(node a, node b)
{
if(a.value == b.value)
return a.pos < b.pos;
else return a.value < b.value;
}

void build(int node, int l, int r)
{
if(l == r){
tr[node] = b[l];
return;
}
int mid = (l + r) >> 1;
build(node << 1, l,mid);
build(node << 1|1, mid + 1, r);
tr[node] = max(tr[node << 1], tr[node << 1|1]);
}
int Max ;
void query(int node, int l, int r, int ql, int qr)
{
if(ql > r || qr < l){
return;
}
if(ql <= l && qr >= r)
{
Max = max(Max,tr[node]);
return;
}
int mid = (l + r) >> 1;
query(node <<1, l, mid, ql, qr);
query(node << 1|1, mid +1, r, ql, qr);
}
int main(){
int n,m ;
cin >> n >> m;
for(int i = 1; i <= n; ++i)
{
scanf("%d",&a[i].value);
d[i] = a[i].value;
a[i].pos = i;
}
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; ++i){
c[i] = a[i].value;
b[i] = a[i].pos;
}
build(1,1,n);
for(int i = 1 ;i <= n; ++i)
{
int pos = lower_bound(c + 1,c + n + 1, d[i] + m) - c;
if(pos == n + 1){
ans[i] = -1;
continue;
}
Max = -1;
query(1,1,n,pos,n);
if(Max <= i)
ans[i] = -1;
else ans[i] = Max - i - 1;
}
for(int i = 1; i <= n; ++i)
{
printf("%d%c",ans[i],i==n?'\n':' ');
}
}