Description
你有一个长度为n 的排列P 与一个正整数K
你可以进行如下操作若干次使得排列的字典序尽量小
对于两个满足|i-j|>=K 且|Pi-Pj| = 1 的下标i 与j,交换Pi 与Pj
对于100% 的数据满足n <= 500000
Analysis
直接做P不知能不能做,但是另一个思路是弄出Q[P[i]]=i,然后依然要求Q字典序尽量小
转化模型:我们每次可以交换Q中相邻两个数,当且仅当他们的差>=K
也就是说,对于Q[i],Q[j],如果|Q[i]-Q[j]|< K,i和j的相对位置永远不可能改变
那么序列中最多有O(N^2)个确定的相对关系,尝试连边,发现会构成一个DAG
那么Q最小的字典序就是DAG上字典序最小的拓扑序,可以做到O(N^2)
但是,其实可以发现连的边有许多是无用的,仔细分析发现每个位置i最多向后连出两条边,即大于Q[i]的最靠左的,和小于Q[i]最靠左的。
这样边数变成O(n),复杂度为寻找相对关系的复杂度,可以使用数据结构做到O(nlogn)
Code
#include<set>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
#define efo(i,v,u) for(int i=last[v],u=to[i];i;i=next[i],u=to[i])
#define mset(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
char ch;
void read(int &n)
{
n=0;
for(ch=getchar();ch<'0' || ch>'9';ch=getchar());
for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';
}
const int N=5e5+5,M=2e6+5,INF=2139062143;
int n,m,a[N],b[N],final[N],ans[N],in[N],tr[N<<2];
int tot,to[M],next[M],last[N];
void link(int u,int v){in[v]++,to[++tot]=v,next[tot]=last[u],last[u]=tot;}
struct node
{
int x;
node(int x0){x=x0;}
friend bool operator <(node n1,node n2)
{
return b[n1.x]<b[n2.x];
}
};
set<node> s;
void add(int v,int l,int r,int x,int y)
{
if(l==r)
{
tr[v]=y;
return;
}
int mid=(l+r)>>1;
if(x<=mid) add(v+v,l,mid,x,y);
else add(v+v+1,mid+1,r,x,y);
tr[v]=min(tr[v+v],tr[v+v+1]);
}
int query(int v,int l,int r,int x,int y)
{
if(x>y) return INF;
if(l==x && r==y) return tr[v];
int mid=(l+r)>>1;
if(y<=mid) return query(v+v,l,mid,x,y);
else
if(x>mid) return query(v+v+1,mid+1,r,x,y);
else
return min(query(v+v,l,mid,x,mid),query(v+v+1,mid+1,r,mid+1,y));
}
int main()
{
freopen("permutation.in","r",stdin);
freopen("permutation.out","w",stdout);
int n,m;
read(n),read(m);
fo(i,1,n) read(a[i]),b[a[i]]=i;
mset(tr,127);
fd(i,n,1)
{
int upper=INF,lower=INF;
if(b[i]<n) upper=query(1,1,n,b[i]+1,min(n,b[i]+m-1));
if(b[i]>1) lower=query(1,1,n,max(1,b[i]-m+1),b[i]-1);
if(upper<=n) link(i,upper);
if(lower<=n) link(i,lower);
add(1,1,n,b[i],i);
}
fo(i,1,n)
if(!in[i]) s.insert(node(i));
while(!s.empty())
{
int x=(*s.begin()).x;s.erase(s.begin());
final[++final[0]]=b[x];
efo(i,x,y)
if(!--in[y]) s.insert(y);
}
fo(i,1,n) ans[final[i]]=i;
fo(i,1,n) printf("%d\n",ans[i]);
return 0;
}