[HEOI2016/TJOI2016]排序
[HEOI2016/TJOI2016]排序
这道题不难,但是挺有意思的。
题解
先讲一些思路:
令\(l=1,r=n\)二分答案,将所有大于\(mid\)的序列修改为\(1\),其余就修改为\(0\),然后对其进行局部排序,升序排序将局部中所有的\(1\)排在后边,降序排序将局部中所有的\(1\)排在前面,最后查询\(q\)位上是否为\(1\),如果\(a_q==1\),则\(ans=mid,l=mid+1\),否则,\(r=mid-1\)。
解释
我们想,因为是全排列,所有\(a_i=1...n\),当我们二分时,如果经过了序列操作最后\(a_q==1\),那么说明我们按照当前的\(ans=mid\)得出的结果是大于等于真正的\(ans\),因为开始时我们将所有大于等于\(mid\)的位置上都赋值为了\(1\),只有当答案在\(a_{mid...r}\)时经过操作\(q\)位置上才为\(1\)。\(a_q==0\)的情况与之相反,因为需要区间修改所以用线段树或者树状数组维护。
代码
#include<bits/stdc++.h>
using namespace std;
const int MN=1e5+100;
int n,m,q,ans,num[MN];
struct node{
int op,l,r;
}a[MN];
void input(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&num[i]);
for(int i=1,op,l,r;i<=m;++i)scanf("%d%d%d",&a[i].op,&a[i].l,&a[i].r);
scanf("%d",&q);
}
#define lc id<<1
#define rc id<<1|1
struct tree{
int l,r,sum;
}t[MN<<2];
int tag[MN<<2];
void pushdown(int id){
if(tag[id]==-1)return;
t[lc].sum=(t[lc].r-t[lc].l+1)*tag[id],tag[lc]=tag[id];
t[rc].sum=(t[rc].r-t[rc].l+1)*tag[id],tag[rc]=tag[id];
tag[id]=-1;
}
void pushup(int id){
t[id].sum=t[lc].sum+t[rc].sum;
}
void build(int id,int l,int r){
t[id].l=l,t[id].r=r,tag[id]=-1;\\因为tag我们赋值为了0,1所以初始化为-1
if(l==r)return;
int mid=(l+r)>>1;
build(lc,l,mid),build(rc,mid+1,r);
}
void update(int id,int l,int r,int k){
if(t[id].l>=l&&t[id].r<=r){
tag[id]=k;
t[id].sum=(t[id].r-t[id].l+1)*k;
return;
}
int mid=(t[id].r+t[id].l)>>1;
if(tag[id]!=-1)pushdown(id);
if(l<=mid)update(lc,l,r,k);
if(r>=mid+1)update(rc,l,r,k);
pushup(id);
}
int get_sum(int id,int l,int r){
if(t[id].l>=l&&t[id].r<=r){
return t[id].sum;
}
int mid=(t[id].r+t[id].l)>>1,ans=0;
pushdown(id);
if(l<=mid)ans+=get_sum(lc,l,r);
if(r>=mid+1)ans+=get_sum(rc,l,r);
return ans;
}
bool pd(int x){
update(1,x,n,1);
update(1,1,x-1,0);
for(int i=1;i<=m;++i){
if(a[i].op){
int cnt=get_sum(1,a[i].l,a[i].r);
if(cnt==0||(a[i].r-a[i].l+1)==cnt)continue;\\全是0,1时不需要修改
update(1,a[i].l,a[i].l+cnt-1,1);
update(1,a[i].l+cnt,a[i].r,0);
}
else{
int cnt=get_sum(1,a[i].l,a[i].r);
if(cnt==0||(a[i].r-a[i].l+1)==cnt)continue;
update(1,a[i].l,a[i].r-cnt,0);
update(1,a[i].r-cnt+1,a[i].r,1);
}
}
return get_sum(1,q,q);
}
void lower(int q){
int l=1,r=n,mid;
while(l<=r){
mid=(l+r)>>1;
pd(mid)==1?ans=mid,l=mid+1:r=mid-1;
}
}
int main(){
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
input();
build(1,1,n);
lower(q);
printf("%d\n",ans);
return 0;
}