zoukankan      html  css  js  c++  java
  • [HEOI2016/TJOI2016]排序

    题目大意

    给出一个 \(1 \sim n\) 的排列,每次操作将 \({[l_i,r_i]}\) 上的数排序(\(opt=0\)升序,\(opt=1\)降序)

    最后有一个询问第\(Q\)位上的数

    \(n,m \leq 100000\)

    解题思路

    这题考虑用二分答案和线段树

    设当前二分值为\(v\)

    将排列中的数\(<v\)的设成\(0\)\(>=v\)的设成\(1\),丢给线段树(\(O(n)\)建树)

    每次排序即统计这个区间内\(0\)\(1\)的个数(相当于在线段树中的询问操作),再按照个数覆盖回去

    操作完后查询第\(Q\)位上的数

    若为\(1\),则答案\(>=v\)

    若为\(0\),则答案\(<v\)

    举个例子

    给定排列1 6 2 5 3 4

    当前二分值\(4\)

    按上面的方式写成01序列变成0 1 0 1 0 1

    此时对\([1,4]\)升序排列变成0 0 1 1 0 1

    只要把\(1\)覆盖后面部分,\(0\)覆盖前面部分就完成了排序操作

    可以用线段树区间修改维护

    注意到,如果最终第\(Q\)位是1,表明这一位至少\(>=4\),这成为了我们继续二分的依据

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    const int maxN=200000,Tsize=10000000;
    int n,m,S[maxN],opt[maxN],l[maxN],r[maxN],Q;
    int T[Tsize],tag[Tsize];
    
    void build(int o,int l,int r,int v){
    	if (l==r){
    		T[o]=S[l]>=v;
    		return;
    	}
    	int mdl=(l+r)>>1;
    	build(o<<1,l,mdl,v);
    	build(o<<1|1,mdl+1,r,v);
    	T[o]=T[o<<1]+T[o<<1|1];
    }
    
    void pushdown(int now,int size){
    	if (~tag[now]){
    		T[now]=(tag[now])?size:0;
    		tag[now<<1]=tag[now<<1|1]=tag[now];
    		tag[now]=-1;
    	}
    }
    
    int query(int o,int l,int r,int L,int R){
    	if (l>r) return 0;
    	if (l>R||r<L) return 0;
    	pushdown(o,r-l+1);
    	if (L<=l&&r<=R) return T[o];
    	int mdl=(l+r)>>1;
    	return query(o<<1,l,mdl,L,R)+query(o<<1|1,mdl+1,r,L,R);
    }
    
    int modify(int o,int l,int r,int L,int R,int v){
    	if (l>r) return 0;
    	pushdown(o,r-l+1);
    	if (l>R||r<L) return T[o];
    	if (L<=l&&r<=R){tag[o]=v;return (v)?(r-l+1):0;}
    	int mdl=(l+r)>>1;
    	return T[o]=modify(o<<1,l,mdl,L,R,v)+modify(o<<1|1,mdl+1,r,L,R,v);
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++) scanf("%d",&S[i]);
    	for (int i=1;i<=m;i++) scanf("%d%d%d",&opt[i],&l[i],&r[i]);
    	scanf("%d",&Q);
    	int L=1,R=n,mdl;
    	while (L<R){
    		mdl=(L+R+1)>>1;
    		memset(T,0,sizeof(T));
    		memset(tag,-1,sizeof(tag));
    		build(1,1,n,mdl);
    		for (int i=1;i<=m;i++){
    			int cnt=query(1,1,n,l[i],r[i]);
    			if (opt[i]){
    				modify(1,1,n,l[i],l[i]+cnt-1,1);
    				modify(1,1,n,l[i]+cnt,r[i],0);
    			}
    			else{
    				modify(1,1,n,l[i],r[i]-cnt,0);
    				modify(1,1,n,r[i]-cnt+1,r[i],1);
    			}
    		}
    		int now=query(1,1,n,Q,Q);
    		if (now) L=mdl;
    		else R=mdl-1;
    	}
    	printf("%d",L);
    }
    
  • 相关阅读:
    三大主流负载均衡软件对比(LVS+Nginx+HAproxy)
    nginx 提示the "ssl" directive is deprecated, use the "listen ... ssl" directive instead
    centos安装nginx并配置SSL证书
    hadoop创建目录文件失败
    The server time zone value 'EDT' is unrecognized or represents more than one time zone.
    脚本启动SpringBoot(jar)
    centos做免密登录
    数据库远程连接配置
    Bash 快捷键
    TCP三次握手四次断开
  • 原文地址:https://www.cnblogs.com/ytxytx/p/9418127.html
Copyright © 2011-2022 走看看