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

    题目:P2824 [HEOI2016/TJOI2016]排序

    思路:

    线段树专题讲的。
    讲过不只一次了,方法挺巧妙的。

    这道题并不是真的需要使用线段树来做排序。
    • 考虑这道题的特殊性质,发现我们只需要求最后一个元素的大小。
    • 由于是全排列,我们可以直接二分答案x,将排列中大于等于x的标记为1,小于x的元素标记为0,维护一颗支持区间覆盖、查询区间和的线段树。每次排序时,查询区间中0、1的个数,之后若是升序排列将前面一段覆盖成0、后一段覆盖成1,降序排列则是反过来。
    • 完成操作后,只需查询所需位置的权值即可完成二分的检验工作,总
    复杂度(O(nlog^2n))

    在线算法先咕着,以后再填。


    Code:

    #include <bits/stdc++.h>
    using namespace std;
    const int N=2e5+5;
    int n,m,pos,a[N],b[N];
    struct data{
    	int type,l,r;
    }q[N];
    struct Tree{
    	int l,r,sum,tag;
    #define l(p) (node[p].l)
    #define r(p) (node[p].r)
    #define sum(p) (node[p].sum)
    #define tag(p) (node[p].tag)
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    }node[N<<2];
    void build(int p,int l,int r){
    	l(p)=l;r(p)=r;tag(p)=-1;
    	if(l==r) return (void) (sum(p)=b[l]);
    	int mid=(l(p)+r(p))>>1;
    	build(ls(p),l,mid);
    	build(rs(p),mid+1,r);
    	sum(p)=sum(ls(p))+sum(rs(p));
    }
    void upd(int p,int v){
    	tag(p)=v;
    	sum(p)=(r(p)-l(p)+1)*v;
    }
    void pdown(int p){
    	if(tag(p)!=-1){
    		upd(ls(p),tag(p));
    		upd(rs(p),tag(p));
    		tag(p)=-1;
    	}
    }
    int query(int p,int L,int R){
    	if(l(p)>R||r(p)<L) return 0;
    	if(L<=l(p)&&r(p)<=R) return sum(p);
    	pdown(p);
    	return query(ls(p),L,R)+query(rs(p),L,R);
    }
    void Set(int p,int L,int R,int v){
    	if(l(p)>R||r(p)<L) return;
    	if(L<=l(p)&&r(p)<=R) return upd(p,v);
    	pdown(p);
    	Set(ls(p),L,R,v);
    	Set(rs(p),L,R,v);
    	sum(p)=sum(ls(p))+sum(rs(p));
    }
    bool check(int mid){
    	for(int i=1;i<=n;++i) b[i]=(a[i]>=mid);
    	build(1,1,n);
    	for(int i=1;i<=m;++i){
    		int cnt=query(1,q[i].l,q[i].r);
    		int len=q[i].r-q[i].l+1;
    		if(q[i].type==0) Set(1,q[i].l,q[i].l+len-cnt-1,0),Set(1,q[i].l+len-cnt,q[i].r,1);
    		else Set(1,q[i].l,q[i].l+cnt-1,1),Set(1,q[i].l+cnt,q[i].r,0);
    	}
    	return query(1,pos,pos); 
    }
    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].type,&q[i].l,&q[i].r);
    	scanf("%d",&pos);
    	int l=1,r=n,ans=1;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(check(mid)) ans=max(ans,mid),l=mid+1;
    		else r=mid-1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Windows API 的数据类型与 Delphi 数据类型对照表
    Delphi 编译错误信息表
    Delphi中的容器类
    Delphi 快捷键
    代码折叠
    [转]Delphi中record的使用
    [转]常用公共函数单元
    Delphi 运行时错误信息表
    C#调用Win32 的API函数User32.dll
    [转]Delphi程序启动参数的读取
  • 原文地址:https://www.cnblogs.com/yu-xing/p/11253057.html
Copyright © 2011-2022 走看看