【NOIP2016模拟7.11】排序

来源:互联网 发布:php 正式表达式 验证qq 编辑:程序博客网 时间:2024/05/03 18:29

Description

这里写图片描述

Input

这里写图片描述

Output

拍完序后第k位上的数字

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5

Data Constraint

30%:n,m<=300
100% n,m<=100000

Solution

对于30分,直接按照操作暴力即可,然而数据太水,可以水出60分。
对于100%显然是不能直接暴力的。可以想到二分答案。
分析复杂度,发现对于每次操作,必须不大于log2(n)才能,那么想到了什么?线段树!
对于二分的答案,将大于这个的数变为1,小于的变为0。对于一个区间,从小到大排序就是把0堆在前面,1放在后面,从大到小排序则相反。这可以用线段树区间修改来做到。
最后再按照第k位看看是0还是1来修改区间。
注意线段树的归零

Code

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 1010000#define fo(i,a,b) for(int i=a;i<=b;i++)using namespace std;int n,m,a[N],c[N],t[N*2][2],lazy[N*2];struct noo{    int o,x,y;};noo q[N];void down(int v,int i,int j){    int m=(i+j)/2;    t[v*2][lazy[v]]=(m-i+1);t[v*2][1-lazy[v]]=0;    t[v*2+1][lazy[v]]=(j-m);t[v*2+1][1-lazy[v]]=0;    lazy[v*2]=lazy[v*2+1]=lazy[v];lazy[v]=-1;}void build(int v,int i,int j){    lazy[v]=-1;    if (i==j) {t[v][c[i]]=1;t[v][1-c[i]]=0;return;}    build(v*2,i,(i+j)/2);build(v*2+1,(i+j)/2+1,j);    t[v][0]=t[v*2][0]+t[v*2+1][0];    t[v][1]=t[v*2][1]+t[v*2+1][1];}int find(int v,int i,int j,int x,int y){    if(i==x&&j==y){return t[v][0];}    int m=(i+j)/2;if(lazy[v]!=-1)down(v,i,j);    if(y<=m) return find(v*2,i,m,x,y);    else if(x>m) return find(v*2+1,m+1,j,x,y);         else return find(v*2,i,m,x,m)+find(v*2+1,m+1,j,m+1,y);}void change(int v,int i,int j,int x,int y,int z){    if(i==x&&j==y) {lazy[v]=z;t[v][z]=y-x+1;t[v][1-z]=0;return;}    int m=(i+j)/2;if (lazy[v]!=-1) down(v,i,j);    if(y<=m) change(v*2,i,m,x,y,z);    else if(x>m) change(v*2+1,m+1,j,x,y,z);         else change(v*2,i,m,x,m,z),change(v*2+1,m+1,j,m+1,y,z);    t[v][0]=t[v*2][0]+t[v*2+1][0];    t[v][1]=t[v*2][1]+t[v*2+1][1];}int main(){    freopen("4605.in","r",stdin);//  freopen("4605.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,n) scanf("%d",&a[i]);    fo(i,1,m)    {        int op,x,y;scanf("%d%d%d",&q[i].o,&q[i].x,&q[i].y);    }    int qq;scanf("%d",&qq);    memset(lazy,-1,sizeof(lazy));    int l=1,r=n;    for(;l+1<r;)    {        int mid=(l+r)/2;        fo(i,1,n) c[i]=a[i]>=mid?1:0;        build(1,1,n);        fo(i,1,m){            int k=find(1,1,n,q[i].x,q[i].y);            int jy=q[i].o;if(jy==1) k=(q[i].y-q[i].x+1)-k;            if (k!=q[i].y-q[i].x+1&&k!=0) change(1,1,n,q[i].x,q[i].x+k-1,jy),change(1,1,n,q[i].x+k,q[i].y,1-jy);        }        int k=1-find(1,1,n,qq,qq);        if(k==1) l=mid;else r=mid;    }    int mid=l;    fo(i,1,n) c[i]=a[i]>=mid?1:0;    build(1,1,n);    fo(i,1,m){        int k=find(1,1,n,q[i].x,q[i].y);        int jy=q[i].o;if(jy==1) k=(q[i].y-q[i].x+1)-k;        if (k!=q[i].y-q[i].x+1&&k!=0) change(1,1,n,q[i].x,q[i].x+k-1,jy),change(1,1,n,q[i].x+k,q[i].y,1-jy);    }    int k=1-find(1,1,n,qq,qq);      if(k==1) r=l;    printf("%d",r);}
1 0
原创粉丝点击