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;
}

  

猜你喜欢

转载自www.cnblogs.com/Aya-Uchida/p/11489292.html