• 题解


    [HEOI2016/TJOI2016]排序

    题目描述

    给出一个 1 到 n 的排列,现在对这个排列序列进行 m 次局部排序,排序分为两种:

    • 0 l r 表示将区间 ([l,r]) 的数字升序排序
    • 1 l r 表示将区间 ([l,r]) 的数字降序排序

    注意,这里是对下标在区间 ([l,r]) 内的数排序。
    最后询问第 q 位置上的数字。
    解题思路

    注意询问只有一个,我们可以很难想到用二分答案,假设答案是mid,然后把所有大于等于mid的数

    当做1,小于mid的数当做0,这样我们可以吧排序问题转化成了区间变成问题,我们就可以用线段树

    来维护了,我们可以统计出线段树每个区间中1的个数,查询要排序的区间中1的个数记为cnt,如果

    按降序排,前cnt个数变1,剩下的变为0,最后查找要询问的数,如果是1,二分答案向左半边找,反

    之向右半边找。

    #include<iostream>
    #include<cstdio>
    #define l(o) (o<<1)
    #define r(o) (o<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    const int N=2e5+7;
    int n,m,p;
    int a[N];
    
    struct node{
    	int opt,l,r;
    }q[N];
    
    int sum[N<<2],tag[N<<2];
    
    void modify(int o,int l,int r,int val){
    	tag[o]=val;
    	sum[o]=(r-l+1)*val;
    }
    
    void up(int o){
    	sum[o]=sum[l(o)]+sum[r(o)];
    }
    
    void down(int o,int l,int r){
    	if(tag[o]!=-1){
    		modify(l(o),l,mid,tag[o]);
    		modify(r(o),mid+1,r,tag[o]);
    		tag[o]=-1;
    	}
    }
    
    void build(int o,int l,int r,int x){
    	tag[o]=-1;
    	if(l==r){
    		sum[o]=(a[l]>=x);
    		return;
    	}
    	build(l(o),l,mid,x);
    	build(r(o),mid+1,r,x);
    	up(o);
    }
    
    void change(int o,int l,int r,int L,int R,int val){
    	if(L<=l&&R>=r){
    		modify(o,l,r,val);
    		return;
    	}
    	down(o,l,r);
    	if(L<=mid)change(l(o),l,mid,L,R,val);
    	if(R>mid)change(r(o),mid+1,r,L,R,val);
    	up(o);
    }
    
    int ask(int o,int l,int r,int L,int R){
    	if(L<=l&&R>=r){
    		return sum[o];
    	}
    	down(o,l,r);
    	int res=0;
    	if(L<=mid)res+=ask(l(o),l,mid,L,R);
    	if(R>mid)res+=ask(r(o),mid+1,r,L,R);
    	return res;
    }
    
    int judge(int x){
    	 build(1,1,n,x);
    	 int cnt;
    	 for(int i=1;i<=m;i++){
    	 	cnt=ask(1,1,n,q[i].l,q[i].r);
    	 	if(q[i].opt==1){
    	 		if(cnt!=0)change(1,1,n,q[i].l,q[i].l+cnt-1,1);
    	 		change(1,1,n,q[i].l+cnt,q[i].r,0);
    			  
    	 	}else{
    	 		change(1,1,n,q[i].l,q[i].r-cnt,0);
    	 		if(cnt!=0)change(1,1,n,q[i].r-cnt+1,q[i].r,1);
    			 
    	 	}
    	 }
    	 return ask(1,1,n,p,p);
    //	 return 0;
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	for(int i=1;i<=m;i++){
    		scanf("%d%d%d",&q[i].opt,&q[i].l,&q[i].r);
    	} 
    	scanf("%d",&p);
    	int l1=1,r1=n;
    	int ans;
    	while(l1<=r1){
    		int mid1=(l1+r1)>>1;
    		if(judge(mid1)){
    			ans=mid1;
    			l1=mid1+1;
    		}else r1=mid1-1;
    	}
    	cout<<ans;
    }
    
  • 相关阅读:
    jQuery 删除元素
    jQuery 添加元素
    jQuery 捕获
    jQuery 链
    jQuery Callback
    jQuery 停止动画
    jQuery 动画
    jQuery 滑动
    jQuery 淡入淡出
    SP2010开发和VS2010专家"食谱"--第七章节--使用客户端对象模型
  • 原文地址:https://www.cnblogs.com/Aswert/p/13369022.html
Copyright © 2020-2023  润新知