jzoj5947 初音未来
Description
Hercier作为一位喜爱Hatsune Miku的OIer,痛下决心,将Vocaloid买回了家。打开之后,你发现界面是一个长为n的序列,代表音调,并形成了全排列。你看不懂日语,经过多次尝试,你只会用一个按钮:将一段区间按升序排序。不理解音乐的Hercier决定写一个脚本,进行m次操作,每次对一段区间进行操作。可惜Hercier不会写脚本,他找到了在机房里的你,请你模拟出最后的结果。
Solution
看到暴力有七十分还想什么(●’◡’●)
考虑记录所有相邻的逆序对。区间排序本质是交换相邻位置使得区间内不存在逆序对,那么我们用set记录一下所有的相邻逆序对,每次二分出区间内最靠左端点的相邻逆序对交换,然后判断是否产生了新的相邻逆序对即可
由于长度为n的排列逆序对是O(n2)级别的,因此复杂度为(n2+m)logn
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <set>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int N=20005;
std:: set <int> set;
int a[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
freopen("miku.in","r",stdin);
freopen("miku.out","w",stdout);
int n=read(),m=read(),L=read(),R=read();
rep(i,1,n) {
a[i]=read();
if (a[i-1]>a[i]) set.insert(i-1);
}
for (;m--;) {
int l=read(),r=read();
for (int it=*set.lower_bound(l);it>=l&&it<r;it=*set.lower_bound(l)) {
set.erase(it);
std:: swap(a[it],a[it+1]);
if (it>1&&a[it-1]>a[it]) set.insert(it-1);
if (it<n&&a[it+1]>a[it+2]) set.insert(it+1);
}
}
rep(i,L,R) printf("%d ", a[i]);
return 0;
}