https://nanti.jisuanke.com/t/41303
题意:就是构造字符串 ,给定一个序列(无重复,长度为n),现在让你构造n个序列问你这n个序列的长度,限制条件是这样的:第一个序列的开头是1,第二个序列的开头是2,依次类推,但是每个序列是单调递减的,并且每个序列往后扩必须满足这个已知数字在原序列位置的|posj-k|--|posj+k|的区间内找扩展的数,看样例理解吧。
题解:因为构造的序列是单调递减的并且必须在区间内找,即转换为在区间【l,r】内找小于X的最大的数即可
所以对原序列排序在依次插入,依次查询,目的是在到查 i 时,区间里只有小于 i 的数,在考虑区间即可。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
int a[maxn];
struct node{
int x;
int id;
}s[maxn];
bool cmp(node a,node b){
return a.x<b.x;
}
int mx[maxn*4];
void build(int l,int r,int p){
if(l==r){
mx[p]=0; return ;
}
int mid=(l+r)/2;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
mx[p]=max(mx[p<<1],mx[p<<1|1]);
}
void update(int l,int r,int id,int pos,int p){
if(l==r){
mx[p]=max(mx[p],pos); return ;
}
int mid=(l+r)/2;
if(id<=mid) update(l,mid,id,pos,p<<1);
else update(mid+1,r,id,pos,p<<1|1);
mx[p]=max(mx[p<<1],mx[p<<1|1]);
}
int quert(int l,int r,int L,int R,int p){
if(L<=l&&r<=R) {
return mx[p];
}
int mid=(l+r)/2;
int ans=0;
if(L<=mid) ans=max(ans,quert(l,mid,L,R,p<<1));
if(R>mid) ans=max(ans,quert(mid+1,r,L,R,p<<1|1));
return ans;
}
int ans[maxn];
int main(){
int t; cin>>t;
while(t--){
int n,k; cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>s[i].x; s[i].id=i;
}
sort(s+1,s+n+1,cmp);
build(1,n,1);
for(int i=1;i<=n;i++){
int l=s[i].id-k; if(l<=1) l=1;
int r=s[i].id+k; if(r>=n) r=n;
int p=quert(1,n,l,r,1);
// cout<<p<<" -- "<<endl;
if(p==0) ans[i]=1;
else ans[i]=ans[p]+1;
if(i<n) cout<<ans[i]<<" ";
else cout<<ans[i]<<endl;
update(1,n,s[i].id,s[i].x,1);
}
}
return 0;
}
//网上有个老哥是主席树写法学习了一下https://www.cnblogs.com/xusirui/p/11462666.html
老哥的思路就是:当前区间[l,r]的sum(数字个数)为0则剪枝,l==r时,如果l<k说明l是k的前驱,否则说明不存在k的前驱,查找时,如果k<=m+1(m=(l+r)/2),返回递归求左区间的答案(注意为什么是m+1,因为当k<=m+1时,小于k的值必定只可能出现在左区间[l,m]中),否则查找右区间,当递归右区间有解,则必为最优解,直接返回这个解即可,当右区间无解,才继续递归左区间求解。 主席树上剪枝搜索。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
struct node{
int l;
int r;
int sum;
int mx;
}T[maxn*4];
int a[maxn],root[maxn],cnt;
void update(int l,int r,int &x,int y,int pos){
T[++cnt]=T[y];
T[cnt].sum++;
T[cnt].mx=(pos,T[cnt].mx);
x=cnt;
if(l==r) return ;
int mid=(l+r)/2;
if(pos<=mid) update(l,mid,T[x].l,T[y].l,pos);
else update(mid+1,r,T[x].r,T[y].r,pos);
}
int quert(int l,int r,int x,int y,int k){//在区间内找小于K的最大的 ;
if(T[y].sum-T[x].sum==0) return 0;
if(l==r){
if(l<k) return l;
return 0;
}
int mid=(l+r)/2;
if(k<=mid+1) return quert(l,mid,T[x].l,T[y].l,k);
int res=quert(mid+1,r,T[x].r,T[y].r,k);
if(res!=0) return res;
else return quert(l,mid,T[x].l,T[y].l,k);
}
struct num_node{
int x;
int id;
}s[maxn];
bool cmp(num_node a,num_node b){
return a.x<b.x;
}
int ans[maxn];
int main(){
int t; cin>>t;
while(t--){
cnt=0;//注意 ,负责RE
int n,k; cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>s[i].x; s[i].id=i;
update(1,n,root[i],root[i-1],s[i].x);
}
sort(s+1,s+n+1,cmp);
for(int i=1;i<=n;i++){
int l=s[i].id-k; if(l<=1) l=1;
int r=s[i].id+k; if(r>=n) r=n;
int p=quert(1,n,root[l-1],root[r],s[i].x);
if(p==0) ans[i]=1;
else ans[i]=ans[p]+1;
if(i<n) cout<<ans[i]<<" ";
else cout<<ans[i]<<endl;
}
}
return 0;
}