Atcoder 题面传送门 & 洛谷题面传送门

咦?鸽子 tzc 来补题解了?奇迹奇迹(

首先考虑什么样的排列可以得到。我们考虑 \(p\) 的逆排列 \(q\),那么每次操作的过程从逆排列的角度思考,就可视作每次在逆排列中交换两个相邻,且元素值之差 \(\ge k\) 的元素。注意到对于两个元素 \(x,y\),如果 \(|x-y|<k\),那么我们肯定永远无法交换它们,它们的相对位置顺序也永远无法改变,因为要改变它们的相对顺序必须交换它们。而一对 \(|q_i-q_j|<k,i<j\) 的 \((i,j)\) 恰好对应一对 \(p_i<p_j,|i-j|<k\) 的 \((i,j)\)。因此对于相距 \(<k\) 的位置,它们的相对大小顺序不能发生变化。而我们能够证明,如果两个排列 \(p,p'\),满足它们相距 \(<k\) 的位置上的元素相对位置大小不变,那么它们之间就能够互相转化,证明我也不太会,一个感性地想法是,我们记排列 \(q\) 满足 \(p\circ q=p'\),那么我们每次总能交换两个数,使得 \(q\) 逆序对大小减一,因此它们能够互相转化。

我们考虑对于 \(|i-j|<k\),如果 \(p_i<p_j\) 则连一条 \(i\to j\) 的边,否则连一条 \(j\to i\) 的边,那么不考虑复杂度的问题,我们的目标就是给每个点赋上一个标号 \(r_i\),使得对于所有有向边 \(u\to v\),都有 \(r_u<r_v\),并且 \(r\) 的字典序尽可能小。这是一个经典问题,考虑这样的过程,我们建反图然后拓扑排序,每次取出编号最大的点然后在上面填 \(n,n-1,\cdots\) 以此类推,类似的题有这个(它是道 Ag 的题但代码异常短)。但是暴力建图复杂度是 \(nk\) 的,无法通过。不过注意到此题建图方式很特殊,\(n^2\) 建边+特殊建图方式 \(=n\log n\)(暴论),注意到一个点 \(x\) 度为 \(0\),当且仅当 \(p_x\) 为 \([x-k+1,x+k-1]\) 的最大值,因此我们考虑用线段树维护这个过程,先一遍扫过去将所有度为 \(0\) 的点压入优先队列,然后每次取出一个点 \(x\) 时,就将 \(p_x\) 改为 \(-\infty\),然后松弛与其相连的点即可。不难发现每次松弛只有 \([x-k+1,x-1]\) 中最大值的位置和 \([x+1,x+k-1]\) 最大值的位置是有用的,只用松弛这两个点即可。

时间复杂度 \(n\log n\)。

const int MAXN=5e5;
int n,m,p[MAXN+5],res[MAXN+5];
struct node{int l,r;pii mx;} s[MAXN*4+5];
void pushup(int k){s[k].mx=max(s[k<<1].mx,s[k<<1|1].mx);}
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;if(l==r) return s[k].mx=mp(p[l],l),void();
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
pushup(k);
}
void modify(int k,int p,pii v){
if(s[k].l==s[k].r) return s[k].mx=v,void();
int mid=s[k].l+s[k].r>>1;
(p<=mid)?modify(k<<1,p,v):modify(k<<1|1,p,v);
pushup(k);
}
pii query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return s[k].mx;
int mid=s[k].l+s[k].r>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}
priority_queue<int> q;
bool inq[MAXN+5];
void check(int x){
if(!x||inq[x]) return;
if(x==query(1,max(x-m,1),min(x+m,n)).se)
q.push(x),inq[x]=1;
}
int main(){
scanf("%d%d",&n,&m);--m;
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
build(1,1,n);int c=n;
for(int i=1;i<=n;i++) check(i);
while(!q.empty()){
int x=q.top();q.pop();res[x]=c--;
// printf("%d\n",x);
modify(1,x,mp(-INF,0));
check(query(1,max(x-m,1),x).se);
check(query(1,x,min(x+m,n)).se);
} for(int i=1;i<=n;i++) printf("%d\n",res[i]);
return 0;
}

最新文章

  1. CSS常用布局学习笔记
  2. [zt]java synchronized详解
  3. css3 transform的基本用法和介绍
  4. mac下 ssh免密码登陆设置
  5. centos 单独安装PHP的mysql和mysqli扩展
  6. iOS代码实践总结
  7. shell 中数学计算总结
  8. 16个最棒的jQuery视差滚动效果教程
  9. MySQL教程:数据库具体操作
  10. asp.net从服务器(指定文件夹)下载任意格式的文件到本地
  11. BZOJ 1257 余数之和sum(分块优化)
  12. STM32关于优先级设定的理解 NVIC_SetPriority()
  13. 刘德华夏日Fiesta演唱会上那个表演探戈舞的演员是谁啊?_百度知道
  14. 【Demo 0015】位置服务及地图
  15. SendMessage发送自定义消息及消息响应
  16. UI进阶 即时通讯之XMPP登录、注册
  17. 给IIS添加网站配置权限
  18. jmeter通过BeanShell 脚本,实现对http请求参数的加密
  19. DDD峰会归来话DDD
  20. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU启动那些事(2)- Boot配置(BOOT Pin/eFUSE)

热门文章

  1. Java---String和StringBuffer类
  2. python字符串调用举例
  3. Hive面试题整理(一)
  4. 欧姆龙plc通讯协议格式
  5. spring security中动态更新用户的权限
  6. 面试官问:说说你对Java函数式编程的理解
  7. 【做题记录】[NOI2008] 假面舞会—有向图上的环与最长链
  8. 攻防世界 WEB 高手进阶区 NSCTF web2 Writeup
  9. Linux 系统分区方案 详细教程
  10. redis-sentinel &quot;DENIED Redis is running in protected mode&quot;