AT1984 [AGC001F] Wide Swap

Description

题目链接:AT1984[AGC001F]

给出一个元素集合为 ${1,2,\dots,N}$( $1\leq N\leq 500,000$)的排列 $P$,当有 $i,j (1\leq i<j\leq N)$满足$j-i\geq K (1\leq K\leq N-1)$ 且 $P_{i}-P_{j}==1∣$ 时,可以交换 $P_{i}$ 和 $P_{j}$。

求:可能排列中字典序最小的排列

Solution

令 $P_{a_i}=i$,那么题中的限制条件就改为 $P_i-P_{i-1}\ge k$,而要使原排列字典序最小也就相当于 $a_i$ 的字典序最小。

然后如果 $P_i-P_{i-1}<k$,则 $i,j$ 之间的相对位置无法改变,此时只需要连一条反边,最后跑一边拓扑就好了。

但是如果这样的话建图会达到 $\mathcal O(N^2)$,但不难发现很多边都是重复的,所以可以用线段树优化建图。直接从 $1$ 到 $n$ 扫一遍,对于左边的只需要向其离 $i$ 最近的连边即可,右边同理。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define W while
#define I inline
#define RI register int
#define LL long long
#define Cn const
#define CI Cn int&
#define gc getchar
#define D isdigit(c=gc())
#define pc(c) putchar((c))
using namespace std;
namespace Debug{
Tp I void _debug(Cn char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts I void _debug(Cn char* f,Ty x,Ar... y){W(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,Cn vector<Ty>& V){os<<"[";for(Cn auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug(#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
namespace FastIO{
Tp I void read(Ty& x){char c;int f=1;x=0;W(!D) f=c^'-'?1:-1;W(x=(x<<3)+(x<<1)+(c&15),D);x*=f;}
Ts I void read(Ty& x,Ar&... y){read(x),read(y...);}
Tp I void write(Ty x){x<0&&(pc('-'),x=-x,0),x<10?(pc(x+'0'),0):(write(x/10),pc(x%10+'0'),0);}
Tp I void writeln(Cn Ty& x){write(x),pc('\n');}
}using namespace FastIO;
Cn int N=5e5+10;
int n,k,a[N],b[N],fir[N],nxt[N<<1],son[N<<1],tot,in[N],Ans[N];
vector<int> p;
I void Add(CI x,CI y){in[y]++,nxt[++tot]=fir[x],fir[x]=tot,son[tot]=y;}
#define to son[i]
class SegmentTree{
private:
int T[N<<2];
#define mid (l+r>>1)
#define PT CI x=1,CI l=1,CI r=n
#define LT x<<1,l,mid
#define RT x<<11,mid+1,r
#define PU(x) (T[x]=max(T[x<<1],T[x<<11]))
public:
I void U(CI p,CI v,PT){
if(l==r) return void(T[x]=v);
p<=mid?U(p,v,LT):U(p,v,RT),PU(x);
}
I int Q(CI L,CI R,PT){
if(L<=l&&r<=R) return T[x];
RI S=0;return L<=mid&&(S=max(S,Q(L,R,LT))),R>mid&&(S=max(S,Q(L,R,RT))),S;
}
}T;
priority_queue<int> q;
I void Topo(){
RI u,i;W(!q.empty()) q.pop();for(i=1;i<=n;i++) if(!in[i]) q.push(i);W(!q.empty()){
for(p.push_back(u=q.top()),q.pop(),i=fir[u];i;i=nxt[i]) if(!--in[to]) q.push(to);
}for(i=0;i<n;i++) Ans[p[i]]=n-i;return ;
}
int main(){
RI i,t;for(read(n,k),i=1;i<=n;i++) read(a[i]),b[a[i]]=i;
for(i=1;i<=n;i++) t=T.Q(b[i],min(b[i]+k-1,n)),t&&(Add(b[i],b[t]),0),t=T.Q(max(1,b[i]-k+1),b[i]),t&&(Add(b[i],b[t]),0),T.U(b[i],i);
for(Topo(),i=1;i<=n;i++) writeln(Ans[i]);return 0;
}