2019 Nanjing F. Greedy Sequence(线段树 - 单点修改 区间最大值查询)

链接:https://nanti.jisuanke.com/t/41303
来源:The Preliminary Contest for ICPC Asia Nanjing 2019

在这里插入图片描述

  题意:给我们一个序列(全排列中的某个序列),序列长度为n。现在需要我们用这个序列组成n个长度为n新序列,问每个序列中非零的数字共有多少个?这n个序列的条件就是:第 i 个序列的开头的元素为 i ,从第二个数开始选择的数字一定要比他的前一个数小,不够 n 个数就在序列的后面补零。选择数字的规则:当前数的最后一个数就是[pos[当前数]-k,pos[当前数]+k]这个区间内小于当前数的最大的那个数。
  思路:刚开始我们维护一个所有元素都为 0 的线段树,对于每一个 i,我们都找到每个 < i 最大的值mmmax(题目要求的区间内),找到 < i的最大值得时候,我们就可以将 i 插入到线段树中(便于后面寻找最大值),那么这个序列能够选到的非零数的个数就是ans[i]=ans[mmmax]+1。

#include<bits/stdc++.h>
#define LNode x<<1
#define RNode x<<1|1
using namespace std;

const int Max_n=1e5+10;
int mmax[4*Max_n],a[Max_n],pos[Max_n],ans[Max_n];

void update(int x){
    mmax[x]=max(mmax[LNode],mmax[RNode]);
}

void build(int l,int r,int x){//构建线段树(自顶向下)
    mmax[x]=0;//刚开始全部为0
    if(l==r){ return ; }
    int mid=(l+r)>>1;
    build(l,mid,LNode);
    build(mid+1,r,RNode);
    update(x);
    //build(1,n,1);//从根开始向上建立线段树
}
//线段树查询(自顶向下)
int query(int A,int B,int l,int r,int x){
    if(A<=l&&B>=r) return mmax[x];
    int mid=(l+r)>>1,ans=0;
    if(A<=mid) ans=max(ans,query(A,B,l,mid,LNode));//查询左子树
    if(B>mid) ans=max(ans,query(A,B,mid+1,r,RNode));//查询右子树
    return ans;
}
//p[i]的位置上修改为i
void change(int pos,int v,int l,int r,int x){///单点修改数据(log(n))
    if(l==r) {mmax[x]=v; return ;}
    int mid=(l+r)>>1;
    if(pos<=mid) change(pos,v,l,mid,LNode);
    else change(pos,v,mid+1,r,RNode);
    update(x);
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) ans[i]=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            pos[a[i]]=i;
        }
        build(1,n,1);
        for(int i=1;i<=n;i++){
            int A=max(1,pos[i]-k),B=min(n,pos[i]+k);
            int mmmax=query(A,B,1,n,1);//对于第i个序列,找到<i的最大的数
            change(pos[i],i,1,n,1);
            ans[i]=ans[mmmax]+1;
            //cout<<" pos[i]:"<<pos[i]<<" i:"<<i<<" max:"<<mmmax<<" ans[i]:"<<ans[i]<<endl;
        }
        for(int i=1;i<=n;i++) printf("%d%c",ans[i],i==n?'\n':' ');
    }
    return 0;
}
发布了166 篇原创文章 · 获赞 68 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_42217376/article/details/100516257