1. 程式人生 > >BZOJ4552:[HEOI2016/TJOI2016]排序——題解

BZOJ4552:[HEOI2016/TJOI2016]排序——題解

space -c color www. 排列 大於 數字 好的 作者

https://www.lydsy.com/JudgeOnline/problem.php?id=4552

https://www.luogu.org/problemnew/show/P2824

在2016年,佳媛姐姐喜歡上了數字序列。因而他經常研究關於序列的一些奇奇怪怪的問題,現在他在研究一個難題,需要你來幫助他。這個難題是這樣子的:給出一個1到n的全排列,現在對這個全排列序列進行m次局部排序,排序分為兩種:1:(0,l,r)表示將區間[l,r]的數字升序排序2:(1,l,r)表示將區間[l,r]的數字降序排序最後詢問第q位置上的數字。

聽說你用桶排過了這道題?

聽說這是一道套路題?

(好的啥也不會的我瑟瑟發抖……)

那讓我講一遍套路吧。

當序列變成01序列的時候,利用線段樹即可O(logn)局部排序(就是變成了區間查詢1的個數,然後左右區間修改為0/1)

我們利用這個性質,二分答案mid,則大於等於mid的數為1,小於的為0,進行排序後看q位置是否為1即可。

正確性很好證,設答案為k,則mid>k時p位置一定為0,否則一定為1.

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace
std; typedef double dl; const int N=1e5+5; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==-;ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct data{ int op,l,r; }q[N]; int n,m,p,b[N],c[N];
int tr[N*4],lazy[N*4]; inline void push(int a,int l,int r){ if(lazy[a]==-1)return; int mid=(l+r)>>1; tr[a<<1]=(mid-l+1)*lazy[a];tr[a<<1|1]=(r-mid)*lazy[a]; lazy[a<<1]=lazy[a<<1|1]=lazy[a]; lazy[a]=-1; } inline void build(int a,int l,int r){ if(l==r){ tr[a]=c[l]; return; } int mid=(l+r)>>1; build(a<<1,l,mid);build(a<<1|1,mid+1,r); tr[a]=tr[a<<1]+tr[a<<1|1]; } inline int query(int a,int l,int r,int l1,int r1){ if(r<l1||r1<l)return 0; if(l1<=l&&r<=r1)return tr[a]; int mid=(l+r)>>1; push(a,l,r); return query(a<<1,l,mid,l1,r1)+query(a<<1|1,mid+1,r,l1,r1); } inline void modify(int a,int l,int r,int l1,int r1,int w){ if(r<l1||r1<l)return; if(l1<=l&&r<=r1){ tr[a]=(r-l+1)*w; lazy[a]=w; return; } int mid=(l+r)>>1; push(a,l,r); modify(a<<1,l,mid,l1,r1,w);modify(a<<1|1,mid+1,r,l1,r1,w); tr[a]=tr[a<<1]+tr[a<<1|1]; } bool check(int k){ memset(lazy,-1,sizeof(lazy)); for(int i=1;i<=n;i++) if(b[i]>=k)c[i]=1; else c[i]=0; build(1,1,n); for(int i=1;i<=m;i++){ int l=q[i].l,r=q[i].r; int cnt=query(1,1,n,l,r); if(!q[i].op){ modify(1,1,n,l,r-cnt,0); modify(1,1,n,r-cnt+1,r,1); }else{ modify(1,1,n,l,l+cnt-1,1); modify(1,1,n,l+cnt,r,0); } } return query(1,1,n,p,p); } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++)b[i]=read(); for(int i=1;i<=m;i++){ q[i].op=read(),q[i].l=read(),q[i].r=read(); } p=read(); int l=1,r=n; while(l<r){ int mid=(l+r+1)>>1; if(check(mid))l=mid; else r=mid-1; } printf("%d\n",l); return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4552:[HEOI2016/TJOI2016]排序——題解