传送门:https://agc001.contest.atcoder.jp/tasks/agc001_f
s
o
l
u
t
i
o
n
solution
solution:
直接做肯定不好做,尝试转化一下模型
原本序列
a
i
{a_i}
ai表示
i
i
i这个下标的值
新序列
b
i
b_i
bi表示值为
i
i
i的下标
这有什么用呢?
原本的交换操作就变成相邻交换。
我们发现每个数字与后面和他绝对值之差<k的相对位置不会变了
可以归纳证明这个相对位置就足够充分的限制了最后的序列
然后我们就直接拓扑序来做就行了
但是边数可能很多怎么办?
对于对于
{
b
i
}
\{b_i\}
{bi}中的第
i
i
i个元素,如果大于小于分开考虑,我们可以发现在一个限制里面,记
i
i
i的连到的集合为
s
s
s那么
s
s
s集合中两两都能产生限制。故
i
i
i只要向
s
s
s里面最靠前的元素连边即可。
线段树维护区间极值即可。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define ls root*2
#define rs root*2+1
int rd()
{
int sum = 0;char c = getchar();bool flag = true;
while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
if(flag) return sum;
else return -sum;
}
const int p = 1e9+7;
const int INF = 1e9;
int n,k;
int a[501000],b[501000],du[501000];
int ans[501000];
int tr[2001000];
int linkk[501000],t;
struct node{int n,y;}e[1001000];
void add(int root,int l,int r,int pl,int v)
{
if(l == r) {tr[root] = v;return;}
int mid = l+r>>1;
if(pl <= mid) add(ls,l,mid,pl,v);
else add(rs,mid+1,r,pl,v);
tr[root] = min(tr[ls],tr[rs]);
}
void dele(int root,int l,int r,int pl)
{
if(l == r) {tr[root] = INF;return;}
int mid = l+r>>1;
if(pl <= mid) dele(ls,l,mid,pl);
else dele(rs,mid+1,r,pl);
tr[root] = min(tr[ls],tr[rs]);
}
int ask(int root,int l,int r,int x,int y)
{
if(l > y || r < x) return INF;
if(x <= l && r <= y) return tr[root];
int mid = l+r>>1;
return min(ask(ls,l,mid,x,y),ask(rs,mid+1,r,x,y));
}
void insert(int x,int y)
{
e[++t].y = y;e[t].n = linkk[x];linkk[x] = t;du[y]++;
}
priority_queue<int>q;
int main()
{
n = rd();k = rd();rep(i,1,n) a[i] = rd(),b[a[i]] = i;
memset(tr,10,sizeof(tr));
if(k == 1)
{
rep(i,1,n) printf("%d\n",i);
return 0;
}
rep(i,1,n) add(1,1,n,b[i],i);
rep(i,1,n)
{
int t = ask(1,1,n,b[i]-k+1,b[i]-1);
if(t > i && t <= n)insert(b[i],b[t]);
t = ask(1,1,n,b[i]+1,b[i]+k);
if(t > i && t <= n)insert(b[i],b[t]);
dele(1,1,n,b[i]);
}
rep(i,1,n) if(du[i] == 0) q.push(-i);
int tot = 0;
while(!q.empty())
{
ans[-q.top()] = ++tot;
int x = -q.top();q.pop();
for(int i = linkk[x];i;i = e[i].n)
{
du[e[i].y]--;
if(du[e[i].y] == 0) q.push(-e[i].y);
}
}
rep(i,1,n) printf("%d\n",ans[i]);
return 0;
}