JZOJ5947. 【NOIP2018模擬11.02】初音未來(miku)
阿新 • • 發佈:2018-11-07
Description
Hercier作為一位喜愛Hatsune Miku的OIer,痛下決心,將Vocaloid買回了家。開啟之後,你發現介面是一個長為n的序列,代表音調,並形成了全排列。你看不懂日語,經過多次嘗試,你只會用一個按鈕:將一段區間按升序排序。不理解音樂的Hercier決定寫一個指令碼,進行m次操作,每次對一段區間進行操作。可惜Hercier不會寫指令碼,他找到了在機房裡的你,請你模擬出最後的結果。
題解
這裡的m非常的大,而且n很小。
對於70%,是很簡單的,直接二分一個答案,
然後變成0/1的形式,用線段樹來維護1的個數,
排序就直接區間修改。
而對於100%就不能這樣做了。
對於一個任意的全排列,它的逆序對個數,是
級別的,
而將任意一個全排列排序交換的個數就是逆序對個數,
也就是說最多的有效交換隻有不到
次。
用一個線段樹維護一下這個位置與前面的位置是否構成逆序對,
如果有就直接交換,
這樣排序的次數就非常少了。
code
#include<cstdio> #include<algorithm> #include<cstring> #define ll long long #define ls (x<<1) #define rs (x<<1|1) #define M ((l+r)>>1) using namespace std; int n,a[2003],m,stl,str,L,R; int opl,opr,ops,id,z[13],lim; bool bz[8003],s[8003]; char ch; void read(int&n) { for(ch=getchar();ch<'0'|| ch>'9';ch=getchar()); for(n=0;'0'<=ch && ch<='9';ch=getchar())n=(n<<1)+(n<<3)+ch-48; } void build(int x,int l,int r) { bz[x]=0; if(l==r) { s[x]=(a[l]>a[l+1]); return; } int m=M; build(ls,l,m); build(rs,m+1,r); s[x]=s[ls]|s[rs]; } void down(int x) { if(bz[x])bz[ls]=bz[rs]=1,s[ls]=s[rs]=bz[x]=0; } void solve(int x,int l,int r) { down(x); if(l==r) { for(int j=l;j>=L && a[j]>a[j+1];j--) for(int i=j;i<R && a[i]>a[i+1];i++)swap(a[i],a[i+1]); return; } int m=M; if(s[rs])solve(rs,m+1,r); if(s[ls])solve(ls,l,m); } void find(int x,int l,int r) { down(x); if(s[x]==0)return; if(opl<=l && r<=opr) { solve(x,l,r); return; } int m=M; if(m<opr)find(rs,m+1,r); if(opl<=m)find(ls,l,m); } void work(int x,int l,int r) { down(x); if(s[x]==0)return; if(opl<=l && r<=opr) { bz[x]=1;s[x]=0; return; } int m=M; if(opl<=m)work(ls,l,m); if(m<opr)work(rs,m+1,r); s[x]=s[ls]|s[rs]; } void ins(int x,int l,int r) { down(x); if(l==r) { s[x]=1; return; } int m=M; if(opl<=m)ins(ls,l,m);else ins(rs,m+1,r); s[x]=s[ls]|s[rs]; } int main() { freopen("miku.in","r",stdin); freopen("miku.out","w",stdout); read(n);read(m);read(stl);read(str); for(int i=1;i<=n;i++)read(a[i]);a[n+1]=n+1; build(1,1,n); for(int i=1;i<=m;i++) { read(L);read(R); opl=L;opr=R; find(1,1,n); work(1,1,n); if(a[L-1]>a[L])opl=L-1,ins(1,1,n); if(a[R]>a[R+1])opl=R,ins(1,1,n); } for(int i=stl;i<=str;i++)printf("%d ",a[i]); }