1 条题解

  • 0
    @ 2026-5-7 19:56:06

    一道好题,由于当初看第一篇题解被困扰了一段时间,因此特意在此解释说明。

    首先,对于一个点对 (i,j)(i,j) (不妨假设 i<ji<j),若 aiaj>K|a_i-a_j|>K,那就意味着两者永远无法交换顺序,这启示我们进行拓扑。

    在不考虑复杂度的情况下,我们可以暴力的连边 iji\to j 表示在 aia_i 放入之前 aja_j 绝对无法填入。

    考虑优化这个过程,首先我们不妨扫描线,求出每个节点的度数,即对于 jjdegj=i<j[aiaj>K]\text{deg}_j=\sum\limits_{i<j}[|a_i-a_j|>K]

    扫描下标,数据结构维护权值即可。

    现在考虑求解答案,显然每次对于当前的开头,我们需要找到一个 degj=0\text{deg}_j=0,将 aja_j 填入当前的开头。

    如果将 jj 填入,我们就需要将所有的和 jj 有连边的 jij\to idegi 1\text{deg}_i\ -1

    但是这是一个二维偏序的问题,不方便动态处理,但是第一篇题解直接选择使用朴素线段树维护,这是为什么呢?

    考虑和 jj 有连边的节点的特性,即 aiaj>K|a_i-a_j|>K,同时根据 i,ji,j 之间的大小关系确定连边方向。

    但是注意到,当 jj 被删除的时候,所有连向他的 ii 也一定被删除了,而剩余的 aiaj>K|a_i-a_j|>K 的节点一定是 jij\to i 的关系。

    因此我们直接朴素线段树维护即可,每次找出最小值,因为一定有解,所以最小值一定是 00。然后线段树更新区间。

    CODE\text{CODE}

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define ll long long
    #define make make_pair
    #define pii pair<int,int>
    #define N 100005
    #define lb(x) (x&(-x))
    #define ls (now<<1)
    #define rs (now<<1|1)
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    int n,k,a[N],bit[N],w[N],tot,deg[N],lz[N*4],ct[N],pos[N];
    pii tr[N*4];
    void add(int x,int w)
    {
    	for(;x<=n;x+=lb(x))bit[x]+=w;
    }
    int que(int x)
    {
    	int ans=0;
    	for(;x>=1;x-=lb(x))ans+=bit[x];
    	return ans;
    }
    void build(int now,int l,int r)
    {
    	if(l==r)
    	{
    		tr[now]={deg[pos[l]],a[pos[l]]};
    		return ;
    	}
    	int mid=(l+r)>>1;
    	build(ls,l,mid);
    	build(rs,mid+1,r);
    	tr[now]=min(tr[ls],tr[rs]);
    }
    void push(int now,int w)
    {
    	lz[now]+=w;
    	tr[now].fi+=w;
    }
    void down(int now)
    {
    	push(rs,lz[now]);
    	push(ls,lz[now]);
    	lz[now]=0;
    }
    void midy(int now,int l,int r,int ql,int qr,int w)
    {
    	if(ql>qr)return ;
    	if(l>=ql&&r<=qr)
    	{
    		push(now,w);
    		return ;
    	}
    	int mid=(l+r)>>1;down(now);
    	if(mid>=ql)midy(ls,l,mid,ql,qr,w);
    	if(mid<qr)midy(rs,mid+1,r,ql,qr,w);
    	tr[now]=min(tr[ls],tr[rs]);
    }
    void del(int now,int l,int r)
    {
    	if(l==r)
    	{
    		tr[now].fi=n+1;
    		return ;
    	}
    	int mid=(l+r)>>1;down(now);
    	if(tr[ls]==tr[now])del(ls,l,mid);
    	else del(rs,mid+1,r);
    	tr[now]=min(tr[ls],tr[rs]);
    }
    signed main()
    {
    	n=read();k=read();
    	for(int i=1;i<=n;i++)a[i]=read(),w[i]=a[i];
    	sort(w+1,w+1+n);
    	for(int i=1;i<=n;i++)
    	{
    		int l=lower_bound(w+1,w+1+n,a[i]-k)-w;
    		int r=upper_bound(w+1,w+1+n,a[i]+k)-w-1;
    		a[i]=lower_bound(w+1,w+1+n,a[i])-w;
    		a[i]+=ct[a[i]];ct[a[i]]++;
    		pos[a[i]]=i;
    		deg[i]=(i-1)-que(r)+que(l-1);
    		add(a[i],1);
    	}
    	build(1,1,n);
    	for(int i=1,l,r;i<=n;i++)
    	{
    		int x=tr[1].se;
    		cout<<w[x]<<"\n"; 
    		l=lower_bound(w+1,w+1+n,w[x]-k)-w-1;
    		r=lower_bound(w+1,w+1+n,w[x]+k+1)-w;
    		del(1,1,n);
    		midy(1,1,n,1,l,-1);
    		midy(1,1,n,r,n,-1);
    	}
    	return 0;
    }
    
    
    • 1

    信息

    ID
    7656
    时间
    4000ms
    内存
    512MiB
    难度
    9
    标签
    递交数
    12
    已通过
    5
    上传者