​LINK​

Ⅰ. s i , 1 = i s_{i,1}=i si,1=i

Ⅱ. s i , j < = s i , j − 1 s_{i,j}<=s_{i,j-1} si,j<=si,j−1

Ⅲ. s i , j s_{i,j} si,j在数组 a a a中的位置是 p o s j pos_j posj,那么 ∣ p o s j − p o s j − 1 ∣ < = k |pos_j-pos_{j-1}|<=k ∣posj−posj−1∣<=k

Ⅳ. s i s_i si应该在字典序上最大

Ⅴ.设此时 s i s_i si的长度为 k k k,在后面补齐 n − k n-k n−k个 0 0 0

先考虑第一个元素为 n n n的情况,设其在 a a a数组中出现位置为 f f f

此时需要找到范围 [ f − k , f + k ] [f-k,f+k] [f−k,f+k]中第一个小于 n n n的数字

这个过程可以用主席树完成,设找到的数字为 n − 3 n-3 n−3

那么 s n − 3 s_{n-3} sn−3的答案就是 s n s_n sn的答案减一

综上所诉,只需要对每个数字标记以下以它开头的答案是多少即可

总复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

在主席树上二分即可

#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
const int maxn = 2e5+10;
int a[maxn],pos[maxn],ans[maxn],n,k;
//*20,也就是2,4,8,16,2^32
int rt[maxn<<5],ls[maxn<<5],rs[maxn<<5],sum[maxn<<5],id;
void insert(int &rt,int pre,int l,int r,int val)
{
if( l>val || r<val ) return;
rt = ++id;
ls[rt] = ls[pre], rs[rt] = rs[pre], sum[rt] = sum[pre];
if( l==r && l==val ){ sum[rt] = 1; return;}
insert( ls[rt],ls[pre],l,mid,val); insert( rs[rt],rs[pre],mid+1,r,val );
sum[rt] = sum[ls[rt]]+sum[rs[rt]];
}
int ask(int rt,int pre,int l,int r,int L,int R)
{
if( l>R || r<L ) return 0;//没找到的意思
if( l>=L && r<=R )
{
if( l==r )
{
if( sum[rt]-sum[pre] ) return l;
else return 0;
}
int x = sum[rs[rt]]-sum[rs[pre]];
int op = ask( rs[rt],rs[pre],mid+1,r,L,R );
if( op ) return op;
else return ask( ls[rt],ls[pre],l,mid,L,R );
}
else
{
int w = ask( rs[rt],rs[pre],mid+1,r,L,R );
if( w ) return w;
else return ask( ls[rt],ls[pre],l,mid,L,R );
}
}
int main()
{
int t; cin >> t;
while( t-- )
{
cin >> n >> k;
for(int i=1;i<=n;i++)
{
cin >> a[i]; pos[a[i]] = i;
insert( rt[i],rt[i-1],1,n,a[i] );
}
ans[1] = 1;
for(int i=2;i<=n;i++)
{
int l = max(1,pos[i]-k), r = min( n,pos[i]+k );
int x = ask( rt[r],rt[l-1],1,n,1,i-1);
ans[i] = ans[x]+1;
}
for(int i=1;i<=n;i++) printf("%d%c",ans[i],i==n?'\n':' ');

for(int i=1;i<=id;i++) sum[i] = ls[i] = rs[i] = rt[i] = 0;
id = 0;
}
return 0;
}