2019徐州网络赛 XKC's basketball team 线段树
网址:https://nanti.jisuanke.com/t/41387
题意:
大家好,我是训练时长两年半的个人练习生蔡徐坤,我的爱好是唱,跳,rap,篮球。
给出一段长度为$n,(n \leq 1e5)$的序列,对每一个数,求出它和它后面比它大$m$的数中间夹着的数的数量,没有输出$-1$。
题解:
直接建线段树,维护最大值,然后查询时对第$i$个数,搜索区间$[i,n]$之中大于$num[i]+m$的值的位置的最大值,具体操作是先限定区间,然后求出所有合法位置,取最大值,如果搜索不到则返回$-1$,(注意考虑$m=0$的情况),剪枝的操作是如果区间最大值小于下界,就不用查找了,然后判断一下是否存在就好了。
AC代码:
#include <bits/stdc++.h> using namespace std; #define ls (k<<1) #define rs ((k<<1)+1) const int MAXN = 5e5 + 5; int num[MAXN]; struct segtree { struct node { int l, r; long long val; }; node tr[MAXN << 2]; void build(int l, int r, int k) { tr[k].l = l, tr[k].r = r; if (l == r) { tr[k].val = num[l]; return; } int m = (l + r) >> 1; build(l, m, ls); build(m + 1, r, rs); tr[k].val = max(tr[ls].val, tr[rs].val); } int query(int l, int r, int k, long long val) { //cout << tr[k].l << " " << tr[k].r << " " << tr[k].val << endl; if (l <= tr[k].l && r >= tr[k].r) { if (tr[k].l == tr[k].r) return tr[k].val >= val ? tr[k].l : -1; int pos = -1; //cout << "==" << tr[ls].val << " " << tr[rs].val << endl; if (tr[rs].val >= val) pos = max(pos, query(l, r, rs, val)); else if (tr[ls].val >= val) pos = max(pos, query(l, r, ls, val)); else pos = -1; return pos; } int m = (tr[k].l + tr[k].r) >> 1; int pos = -1; if (l <= m) pos = max(pos, query(l, r, ls, val)); if (r > m) pos = max(pos, query(l, r, rs, val)); return pos; } }; segtree tr; int main() { int n; long long m; scanf("%d%lld", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", &num[i]); tr.build(1, n, 1); for (int i = 1; i <= n; ++i) { int pos = tr.query(i, n, 1, num[i] + m); //cout << pos << endl; if (pos == i || pos == -1) printf("-1"); else printf("%d", pos - i - 1); printf("%c", i == n ? '\n' : ' '); } return 0; }