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);
}