XKC's basketball team【线段树查询】
XKC , the captain of the basketball team , is directing a train of nn team members. He makes all members stand in a row , and numbers them 1 \cdots n1⋯n from left to right.
The ability of the ii-th person is w_iwi , and if there is a guy whose ability is not less than w_i+mwi+m stands on his right , he will become angry. It means that the jj-th person will make the ii-th person angry if j>ij>i and w_j \ge w_i+mwj≥wi+m.
We define the anger of the ii-th person as the number of people between him and the person , who makes him angry and the distance from him is the longest in those people. If there is no one who makes him angry , his anger is -1−1 .
Please calculate the anger of every team member .
Input
The first line contains two integers nn and m(2\leq n\leq 5*10^5, 0\leq m \leq 10^9)m(2≤n≤5∗105,0≤m≤109) .
The following line contain nn integers w_1..w_n(0\leq w_i \leq 10^9)w1..wn(0≤wi≤109) .
Output
A row of nn integers separated by spaces , representing the anger of every member .
样例输入
6 1 3 4 5 6 2 10
样例输出
4 3 2 1 0 -1
题目大意:
1.给出一个长度为n的数列,给出m的值。问在数列中从右到左第一个比 arr[i] + m 大的值所在位置与 arr[i] 的所在位置之间夹着多少个数。
解题思路:
1.用线段树来记录区间最大值,优先从右子树开始查询是否存在大于 arr[i] + m的值,返回下标即该值在原数列中的位置,即可求得答案。
2.重要的是查询的值必须是在 i 的右边,否则输出 -1
代码如下:
1 #include<stdio.h> 2 #include<algorithm> 3 using namespace std; 4 const int MAXN = 5e5 + 10; 5 6 int n, m; 7 int a[MAXN], ANS[MAXN]; 8 9 struct Tree 10 { 11 int val, l, r; 12 }tree[4 * MAXN]; 13 14 void build(int k, int l, int r) 15 { 16 tree[k].l = l, tree[k].r = r; 17 if(l == r) 18 { 19 tree[k].val = a[l]; 20 return ; 21 } 22 int mid = (l + r) / 2; 23 build(2 * k, l, mid); 24 build(2 * k + 1, mid + 1, r); 25 tree[k].val = max(tree[2 * k].val, tree[2 * k + 1].val); 26 } 27 28 int query(int k, int goal) 29 { 30 if(tree[k].l == tree[k].r) 31 return tree[k].l; 32 if(tree[2 * k + 1].val >= goal) 33 return query(2 * k + 1, goal); 34 else if(tree[2 * k].val >= goal) 35 return query(2 * k, goal); 36 else 37 return -1; 38 } 39 40 int main() 41 { 42 scanf("%d%d", &n, &m); 43 for(int i = 1; i <= n; i ++) 44 scanf("%d", &a[i]); 45 build(1, 1, n); //线段树建树 46 for(int i = 1; i <= n; i ++) 47 { 48 int flag = 0; 49 int ans = query(1, a[i] + m); //由右边开始查询,返回右边第一个大于 a[i] + m值的位置 50 if(ans == -1 || ans <= i) 51 ANS[i] = -1; 52 else if(ans > i) 53 ANS[i] = ans - i - 1; 54 } 55 printf("%d", ANS[1]); 56 for(int i = 2; i <= n; i ++) 57 printf(" %d", ANS[i]); 58 printf("\n"); 59 return 0; 60 }