permutation
Description
你有一个长度为
n
的排列
你可以进行如下操作若干次使得排列的字典序尽量小
对于两个满足|
Data Constraint
n
<=
Solution
转换问题,令
qPi
=
i
,题目变成了令
一种合法的操作定义为,若
q
中相邻的两个位置上的数的差的绝对值大于等于
我们可以观察出一个性质,对于两个数
i
,
根据这个性质,对于所有满足条件的
i
,
当时上述的做法理论上连边数回达到
n2
级别,会超时。
事实上我们每个点可以只连两条边,对于每个
qi
,只向它右边数起第一个比
qi
大 的、满足条件的(即满足
qj
-
qi
<
K
)的
对于每个
qi
,找到它右边满足条件的两个数,用一棵线段树维护即可。时间复杂度
O
(
在构造答案序列的时候,用一个
每一次从
set
中选出一个最小的
qi
选入答案序列中,同时删去与
qi
相连的边,并检查是否有新的点入度刚变为
0
,如有,将这个点加入
当然,也可以不用
set
,用
C
++其他的黑科技也行。
注:上述所述的连边都是指
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define fo(i,j,l) for(int i=j;i<=l;i++)
#define fd(i,j,l) for(int i=j;i>=l;i--)
#define rep(i,j) for(int i=la[j];i;i=ne[i])
using namespace std;
typedef long long ll;
const ll N=5e5+1e3,M=2*N;
int n,m,k,l,o,a,w1,w2,oo,kk;
int q[N],ne[M],lb[M],la[N],t[M*2],d[N],ans[N],p[N];
set<int> op;
void read(int &o)
{
o=0; char ch=' ';
for(;ch<'0'||ch>'9';)ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;
}
void write(int o)
{
int kt=0; char ch[20];
for(;o;o/=10)ch[++kt]='0'+o%10;
fd(i,kt,1)printf("%c",ch[i]);
printf("\n");
}
int min(int a,int b)
{if(a<b)return a;else return b;}
int max(int a,int b)
{if(a>b)return a;else return b;}
void jl(int o,int l,int r)
{
t[o]=n+1; if(l==r)return;
int mid=(l+r)/2;
jl(o*2,l,mid); jl(o*2+1,mid+1,r);
}
void change(int o,int l,int r)
{
if(l==r&&l==w1){t[o]=w2; return;}
if(l>w1||r<w1)return;
int mid=(l+r)/2;
change(o*2,l,mid); change(o*2+1,mid+1,r);
if(t[o*2]<t[o*2+1])t[o]=t[o*2];else t[o]=t[o*2+1];
}
void question(int o,int l,int r)
{
if(l>=w1&&r<=w2){
if(t[o]<kk)kk=t[o];
return;
}
if(l>w2||r<w1)return;
int mid=(l+r)/2;
question(o*2,l,mid); question(o*2+1,mid+1,r);
}
void llb(int a,int b)
{ne[++oo]=la[a]; lb[oo]=b; la[a]=oo; d[b]++;}
void doing()
{
jl(1,1,n);
fd(i,n,1){
kk=n+1; w1=p[i]; w2=min(p[i]+k-1,n);
question(1,1,n);
if(kk!=n+1)llb(p[i],p[kk]);
kk=n+1; w1=max(1,p[i]-k+1); w2=p[i];
question(1,1,n);
if(kk!=n+1)llb(p[i],p[kk]);
w1=p[i]; w2=i;
change(1,1,n);
}
fo(i,1,n)if(!d[i])op.insert(i);
fo(i,1,n){
int y=ans[i]=*op.begin(); op.erase(y);
rep(j,y)
if(!(--d[lb[j]]))op.insert(lb[j]);
}
fo(i,1,n)p[ans[i]]=i;
fo(i,1,n)write(p[i]);
}
void intt()
{
cin>>n>>k;
fo(i,1,n)
read(a),p[a]=i;
}
int main()
{
intt();
doing();
}