解析:
假设当前位置为x 距离不超过k
那么我们可以在[x-k,x] 和 [x,x+k] 去找小于a[x]且最大的数
那么可以利用主席树去解决
因为要找最大的,所以我们贪心地先遍历到右子树,否则再去左子树
#pragma GCC optimize(3 , "Ofast" , "inline")
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10000;
int t,n,k;
int a[N];
struct node
{
int l,r,cnt;
}tr[N*30];
int id[N],rt[N],idx,root[N];
int ans[N];
int build(int l,int r)
{
int p=++idx;
// tr[p].cnt=0;
if(l==r) return p;
int mid=l+r>>1;
tr[p].l=build(l,mid);tr[p].r=build(mid+1,r);
return p;
}
int insert(int p,int l,int r,int x)
{
int q=++idx;
if(l==r){
tr[q].cnt++;
return q;
}
tr[q]=tr[p];
int mid=l+r>>1;
if(x<=mid) tr[q].l=insert(tr[p].l,l,mid,x);
else tr[q].r=insert(tr[p].r,mid+1,r,x);
tr[q].cnt=tr[tr[q].l].cnt+tr[tr[q].r].cnt;
return q;
}
int query(int q,int p,int l,int r,int x)
{
if(l==r)
{
if(l>x) return 0;
return l;
}
int mid=l+r>>1;
int res=0;
int tot=tr[tr[q].l].cnt-tr[tr[p].l].cnt;
int cnt=tr[tr[q].r].cnt-tr[tr[p].r].cnt;
//贪心地去右子树,如果右子树为空那就不用遍历
if(x>mid&&cnt) res=query(tr[q].r,tr[p].r,mid+1,r,x);
//左子树,如果res==0 说明在右子树未找到任何信息,需要去左子树寻找
if(!res&&tot) res=query(tr[q].l,tr[p].l,l,mid,x);
return res;
}
int main()
{
scanf("%d",&t);
while(t--)
{
idx=0;
scanf("%d %d",&n,&k);
memset(tr,0,sizeof tr);
for(int i=1;i<=n;i++) ans[i]=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
id[a[i]]=i;
}
root[0]=build(1,n);
for(int i=1;i<=n;i++) root[i]=insert(root[i-1],1,n,a[i]);
for(int i=1;i<=n;i++)
{
int l=max(1,id[i]-k);
int r=min(n,id[i]+k);
int s1=query(root[r],root[id[i]],1,n,i-1);
int s2=query(root[id[i]-1],root[l-1],1,n,i-1);
int res=max(s1,s2);
if(res==0) ans[i]=1;
else ans[i]=ans[res]+1;
}
for(int i=1;i<=n;i++)
{
if(i==1) printf("%d",ans[i]);
else printf(" %d",ans[i]);
}
printf("\n");
}
}