LOJ2055-「TJOI / HEOI2016」排序
题意:
给出一个1-n的全排列,在给出m个操作,每次会将一个区间的数升序或降序排列,求最后位置q上的数是什么.(n<=1e5)
题解:
我们二分最后位置上的数,然后我们将比这个数小的数赋值为-1,比这个数大的数赋值为1,这个数赋值为0,再用一个支持区间赋值,区间求和的线段树来维护这个数列.对于每个区间,区间和代表的是1的个数减去-1的个数.然后通过维护0所在的位置,我们可以得出区间中-1和1的数量和.通过这两个值,我们可以求出区间中-1的数量和1的数量.然后如果要对这个区间升序排序就将这个区间的前段赋值为-1,将这个区间的后段赋值为1,中间赋值为0.如果降序排序反过来就可以了.最后求出位置q上的值,如果为0表示当前数就是答案,如果为-1表示答案比当前数小,如果为1表示答案比当前数大.复杂度O(m*logn*logn).
#include<cstdio> const int N=1e5; struct node{int l,r,val,tag;}a[N*4+10]; struct data{int l,r; bool v;}b[N+10]; int arr[N+10],pos,n,m,q; void build_tree(int p,int l,int r,int v){ a[p].l=l; a[p].r=r; a[p].tag=0; if(l==r){ if(arr[l]==v) pos=l,a[p].val=0; else a[p].val=arr[l]<v?-1:1; }else{ int mid=(l+r)/2; build_tree(p*2,l,mid,v); build_tree(p*2+1,mid+1,r,v); a[p].val=a[p*2].val+a[p*2+1].val; } } void push_down(int p){ if(!a[p].tag) return; a[p*2].tag=a[p].tag; a[p*2].val=(a[p*2].r-a[p*2].l+1)*a[p].tag; a[p*2+1].tag=a[p].tag; a[p*2+1].val=(a[p*2+1].r-a[p*2+1].l+1)*a[p].tag; a[p].tag=0; } void change(int p,int l,int r,int v){ if(l>r) return; if(a[p].l==l&&a[p].r==r){ a[p].tag=v; a[p].val=(r-l+1)*v; return; } int mid=(a[p].l+a[p].r)/2; push_down(p); if(r<=mid) change(p*2,l,r,v); else if(l>mid) change(p*2+1,l,r,v); else change(p*2,l,mid,v),change(p*2+1,mid+1,r,v); a[p].val=a[p*2].val+a[p*2+1].val; } int query(int p,int l,int r){ if(l>r) return 0; if(a[p].l==l&&a[p].r==r) return a[p].val; int mid=(a[p].l+a[p].r)/2; push_down(p); if(r<=mid) return query(p*2,l,r); else if(l>mid) return query(p*2+1,l,r); else return query(p*2,l,mid)+query(p*2+1,mid+1,r); } int check(int v){ build_tree(1,1,n,v); for(int i=1;i<=m;++i){ bool isin=pos>=b[i].l&&pos<=b[i].r; int v=query(1,b[i].l,b[i].r),num=b[i].r-b[i].l+1-isin; int ln=(num-v)/2,rn=(num+v)/2; if(!b[i].v){ change(1,b[i].l,b[i].l+ln-1,-1); change(1,b[i].r-rn+1,b[i].r,1); if(isin) change(1,pos=b[i].l+ln,b[i].l+ln,0); }else{ change(1,b[i].l,b[i].l+rn-1,1); change(1,b[i].r-ln+1,b[i].r,-1); if(isin) change(1,pos=b[i].l+rn,b[i].l+rn,0); } } return query(1,q,q); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&arr[i]); for(int i=1;i<=m;++i) scanf("%d%d%d",&b[i].v,&b[i].l,&b[i].r); int l=1,r=n; scanf("%d",&q); for(;l!=r;){ int mid=(l+r)/2,v=check(mid); if(v>0) l=mid+1; else if(v<0) r=mid-1; else{ printf("%d",mid); return 0; } } printf("%d",l); return 0; }