补题做到的,没有注意提交人数,
看到题就有一点思路就开始敲了,可以转化为经典的主席树问题,区间查询第k小,但是树状数组代码比较简短;
题目大意
给你一个数组,给了一个k,让你答出,每个数左边第k个比他大的数是多少。
题解
先把所有的数据用结构体或者pair记录原下标,按照权值从大到小排序,转化为离线操作。
从大到小插入数据,每组数据就相当于是一个询问,这样可以保证插入这个数据之前的所有数据都比他大。
所以可以用树状数组去记录权值,也就是他左边出现的数的数量,因为是从大到小已经排过序了,出现过的数是一定要大于当前查询的这个数的。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200010;
int c[N];
struct node
{
int w, idx;
} a[N];
int ans[N], num[N];
int n, k;
bool cmp(node a, node b)
{
if (a.w != b.w)
return a.w > b.w;
else
return a.idx > b.idx;
}
int lowbit(int x)
{
return x & (-x);
}
void add(int x)
{
for (; x <= n; c[x]++, x += lowbit(x))
;
}
int getsum(int x)
{
int ans = 0;
for (; x > 0; ans += c[x], x -= lowbit(x))
;
return ans;
}
bool check(int x, int mid)
{
return getsum(mid - 1) - getsum(x - 1) >= k;
;
}
void solve()
{
scanf("%lld%lld", &n, &k);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i].w);
num[i] = a[i].w;
c[i] = 0;
a[i].idx = i;
}
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++)
{
add(a[i].idx);
if (getsum(a[i].idx - 1) < k)
{
ans[a[i].idx] = -1;
}
else
{
int l = 1, r = a[i].idx - 1;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid, a[i].idx))
l = mid;
else
r = mid - 1;
}
ans[a[i].idx] = num[l];
}
}
for (int i = 1; i <= n; i++)
{
printf("%lld\n",ans[i]);
}
}
signed main()
{
int t;
scanf("%lld", &t);
while (t--)
solve();
}