[HEOI2016/TJOI2016]排序

description

BZOJ
luogu
给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:
\((0,l,r)\)表示将区间\([l,r]\)的数字升序排序
\((1,l,r)\)表示将区间\([l,r]\)的数字降序排序
最后询问第q位置上的数字。

data range

\[n,m\le 10^5 \]

solution

解法1

既然是排序,那我们考虑\(01\)序列。
一个\(01\)序列排序后显然是一段\(0\)+一段\(1\)
因此对于\(01\)序列的排序可以使用区间覆盖+区间求和的线段树做到\(O(logn)\)

考虑如何转换到\([1,n]\)的排列的问题上来。
二分一个值\(x\),把\(a_i\)标记为\([a_i\ge x]\)
然后模拟排序过程,最后可以得到位置\(q\)上的数\(1\),代表其是否\(\ge x\)

复杂度\(O(nlog^2n)\)

解法2

考虑直接模拟这个排序过程。
一开始每个位置都是独立的一段,
进行排序时,会有一些段被合并成顺序或者倒序,会有一些顺序或倒序的段被拆开。
于是我们可以使用线段树分裂+合并,讨论一下模拟即可。

由于每次线段树分裂最多新增\(O(logn)\)个节点,
初始时有\(O(nlogn)\)个节点,复杂度即为\(O((n+m)logn)\)

Code

解法1

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define FL "a"
#define fi first
#define se second
#define RG register
using namespace std;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-6;
const int mod=1e4;
const int N=4e5+10;
const int M=2e5+10;
const dd pi=acos(-1);
const int inf=2147483647;
const ll INFL=1e18+1;
const ll P=100000;
inline ll read(){
  RG ll data=0,w=1;RG char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
  if(ch=='-')w=-1,ch=getchar();
  while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
  return data*w;
}
inline void file(){
  srand(time(NULL)+rand());
  freopen(FL".in","r",stdin);
  freopen(FL".out","w",stdout);
}

int n,m,q,a[N],op[N],L[N],R[N];
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
int X,sum[N<<2],cov[N<<2];
inline void update(int i){sum[i]=sum[ls]+sum[rs];}
inline void cover(int i,int l,int r,int v){cov[i]=v;sum[i]=(r-l+1)*v;}
inline void pushdown(int i,int l,int r){
  if(cov[i]!=-1){cover(ls,l,mid,cov[i]);cover(rs,mid+1,r,cov[i]);cov[i]=-1;}
}
void build(int i,int l,int r){
  cov[i]=-1;if(l==r){sum[i]=(a[l]>X);return;}
  build(ls,l,mid);build(rs,mid+1,r);update(i);
}
void modify(int i,int l,int r,int x,int y,int v){
  if(x<=l&&r<=y){cover(i,l,r,v);return;}pushdown(i,l,r);
  if(x<=mid)modify(ls,l,mid,x,y,v);
  if(mid<y)modify(rs,mid+1,r,x,y,v);
  update(i);
}
int query(int i,int l,int r,int x,int y){
  if(x<=l&&r<=y)return sum[i];pushdown(i,l,r);int s=0;
  if(x<=mid)s=query(ls,l,mid,x,y);
  if(mid<y)s+=query(rs,mid+1,r,x,y);
  return s;
}

inline bool check(){
  //printf("check:%d\n",X);
  build(1,1,n);
  //for(RG int j=1;j<=n;j++)printf("%d ",query(1,1,n,j,j));puts("");
  for(RG int i=1,x;i<=m;i++){
    x=query(1,1,n,L[i],R[i]);
    if(!op[i])modify(1,1,n,L[i],R[i]-x,0),modify(1,1,n,R[i]-x+1,R[i],1);
    else modify(1,1,n,L[i],L[i]+x-1,1),modify(1,1,n,L[i]+x,R[i],0);
    //for(RG int j=1;j<=n;j++)printf("%d ",query(1,1,n,j,j));puts("");
  }
  return query(1,1,n,q,q);
}

int main()
{
  n=read();m=read();
  for(RG int i=1;i<=n;i++)a[i]=read();
  for(RG int i=1;i<=m;i++){op[i]=read();L[i]=read();R[i]=read();}
  q=read();
  RG int l=1,r=n;
  while(l<r)X=((l+r)>>1),check()?l=X+1:r=X;
  printf("%d\n",l);return 0;
}

解法2

BZOJ都过了,但是洛谷至今未AC...

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define FL "a"
#define fi first
#define se second
#define RG register
using namespace std;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-6;
const int mod=1e4;
const int N=2e5+10;
const int M=2e5+10;
const dd pi=acos(-1);
const int inf=2147483647;
const ll INFL=1e18+1;
const ll P=100000;
inline ll read(){
  RG ll data=0,w=1;RG char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
  if(ch=='-')w=-1,ch=getchar();
  while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
  return data*w;
}
inline void file(){
  srand(time(NULL)+rand());
  freopen(FL".in","r",stdin);
  freopen(FL".out","w",stdout);
}

int n,m,q,qr,o[N];set<int>S;set<int>::iterator tmp;
int rt[N],sz[20*N],s[2][20*N],tot,cal[20*N],top;
inline void recycle(int i){sz[i]=s[0][i]=s[1][i]=0;cal[++top]=i;}
inline int newnode(){return top?cal[top--]:++tot;}

#define mid ((l+r)>>1)
void insert(int &i,int l,int r,int p){
  if(!i)i=newnode();sz[i]++;if(l==r)return;
  p<=mid?insert(s[0][i],l,mid,p):insert(s[1][i],mid+1,r,p);
}
int query(int i,int l,int r,int k){
  if(l==r)return l;
  if(k<=sz[s[0][i]])return query(s[0][i],l,mid,k);
  else return query(s[1][i],mid+1,r,k-sz[s[0][i]]);
}
int merge(int a,int b){
  if(!a||!b)return a|b;
  s[0][a]=merge(s[0][a],s[0][b]);
  s[1][a]=merge(s[1][a],s[1][b]);
  sz[a]+=sz[b];recycle(b);return a;
}
void split(int a,int b,int k){
  int sum=sz[s[0][a]];
  if(k>sum)split(s[1][a],s[1][b]=newnode(),k-sum);
  else swap(s[1][a],s[1][b]);
  if(k<sum)split(s[0][a],s[0][b]=newnode(),k);
  sz[b]=sz[a]-k;sz[a]=k;
}
inline void cut(int p,int k,int r){
  o[k]=o[p];S.insert(k);
  if(!o[p])split(rt[p],rt[k]=newnode(),k-p);
  else swap(rt[p],rt[k]),split(rt[k],rt[p]=newnode(),r-k);
}

int main()
{
  n=read();m=read();
  for(RG int i=1;i<=n;i++)insert(rt[i],1,n,read()),o[i]=0;
  for(RG int i=1;i<=n+1;i++)S.insert(i);
  for(RG int i=1,op,l,r,L,R;i<=m;i++){
    op=read();l=read();r=read();
    tmp=S.lower_bound(l);L=*tmp;if(L!=l)cut(*(--tmp),l,L);
    tmp=S.upper_bound(r);R=*tmp;if(R!=r+1)cut(*(--tmp),r+1,R);
    for(tmp=S.lower_bound(l),tmp++;(*tmp)!=r+1;tmp=S.lower_bound(l),tmp++)
      rt[l]=merge(rt[l],rt[*tmp]),S.erase(tmp);
    o[l]=op;
  }
  q=read();tmp=S.upper_bound(q);qr=*tmp;tmp--;
  if(!o[*tmp])printf("%d\n",query(rt[*tmp],1,n,q-(*tmp)+1));
  else printf("%d\n",query(rt[*tmp],1,n,qr-q));
  return 0;
}

posted @ 2018-11-06 17:37  cjfdf  阅读(196)  评论(0编辑  收藏  举报