AGC001 F Wide Swap
考虑一个转化
我们用p[i]表示权值为i的在原序列中所在的位置为p[i]
这样我们得到了一个p序列
显然的一点原序列操作后字典序最小等价于让p序列操作后字典序最小
我们考虑p序列怎么进行操作
显然的相当于可以交换任意两个相邻的数,前提为两个差值>=k
显然这种操作相当于拓扑排序
考虑i和j(指的是权值),如果i在j(在原序列中)的前面,并且abs(p[i]-p[j])<k
那么不管怎么操作i都在j的前面
然后就得到了一张拓扑图(建图直接用线段树优化,相当于找1-i-1中第一个<k的,因为它不可能通过交换通过i,更不可能到i之前)
然后用个堆来维护一下,贪心跑一下拓扑就ok了
代码如下:
#include<bits/stdc++.h> #define inf 1000000000 #define N 2000005 using namespace std; int n,K,kk,cnt,a[N],p[N],d[N],head[N],val[N],ru[N]; struct Edge{int nxt,to;}e[N]; inline void link(int x,int y){ru[y]++;e[++kk].nxt=head[x];e[kk].to=y;head[x]=kk;} void insert(int k,int l,int r,int x,int y){ if (l==r){d[k]=y;return;} int mid=(l+r)>>1; if (x<=mid) insert(k*2,l,mid,x,y); else insert(k*2+1,mid+1,r,x,y); d[k]=max(d[k*2],d[k*2+1]); } int query1(int k,int l,int r,int x,int y){ if (x>y) return 0; if (x<=l&&y>=r) return d[k]; int mid=(l+r)>>1; if (y<=mid) return query1(k*2,l,mid,x,y); else if (x>mid) return query1(k*2+1,mid+1,r,x,y); else return max(query1(k*2,l,mid,x,mid),query1(k*2+1,mid+1,r,mid+1,y)); } priority_queue<int> Q; inline void topsort(){ for (int i=1;i<=n;i++) if (!ru[i]) Q.push(-i); while (!Q.empty()){ int u=-Q.top();Q.pop(); cnt++;val[u]=cnt; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to;ru[v]--; if (!ru[v]) Q.push(-v); } } } int main(){ scanf("%d%d",&n,&K); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++) p[a[i]]=i; for (int i=1;i<=n;i++){ int pos1=query1(1,1,n,min(n,p[i]+1),min(n,p[i]+K-1)); if (pos1) link(p[pos1],p[i]); pos1=query1(1,1,n,max(1,p[i]-K+1),max(1,p[i]-1)); if (pos1) link(p[pos1],p[i]); insert(1,1,n,p[i],i); } topsort(); for (int i=1;i<=n;i++) printf("%d\n",val[i]); return 0; }