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);
    }
    
  • 相关阅读:
    Flutter 中那么多组件,难道要都学一遍?
    【Flutter实战】自定义滚动条
    Python 为什么只需一条语句“a,b=b,a”,就能直接交换两个变量?
    一篇文章掌握 Python 内置 zip() 的全部内容
    Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性
    Python 3.10 版本采纳了首个 PEP,中文翻译即将推出
    Python 为什么不支持 i++ 自增语法,不提供 ++ 操作符?
    Python 为什么推荐蛇形命名法?
    Python 为什么没有 main 函数?为什么我不推荐写 main 函数?
    Python 为什么不用分号作终止符?
  • 原文地址:https://www.cnblogs.com/ytxytx/p/9418127.html
Copyright © 2011-2022 走看看