zoukankan      html  css  js  c++  java
  • [Tjoi2016&Heoi2016]排序

    题目

    bzoj4552

    题解

    二分q位置上的值mid,然后将所有大于mid的数记为1,小于等于mid的数记为0,用线段树维护区间的和

    对于升序排列,及时将所有为1的数放在右边;降序排列就是将所有为0的数放在右边

    最后判断出p位置为1还是0,若为1,则说明mid小于真实值,l=mid+1;若为0,则mid可能大于真实值(注意是可能),记录ans并r=mid

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath> 
    #define N 1000000
    using namespace std;
     
    int n,m,a[N],q;
    int opt[N],cl[N],cr[N];
     
    struct node{int l,r,sum,d;}T[N];
     
    void pushup(int p){T[p].sum=T[p<<1].sum+T[p<<1|1].sum;}
    void pushdown(int p)
    {
        if(T[p].d==-1) return;
        T[p<<1].sum=(T[p<<1].r-T[p<<1].l+1)*T[p].d;
        T[p<<1|1].sum=(T[p<<1|1].r-T[p<<1|1].l+1)*T[p].d;
        T[p<<1].d=T[p<<1|1].d=T[p].d;
        T[p].d=-1;
    }
     
    void build(int p,int x,int y,int v)
    {
        T[p].l=x;T[p].r=y;T[p].d=-1;
        if(x==y) {T[p].sum=(a[x]>v);return;}
        if(x<y)
        {
            int mid=(x+y)>>1;
            build(p<<1,x,mid,v);
            build(p<<1|1,mid+1,y,v);
            pushup(p);
        }
    }
     
    int query(int p,int x,int y)
    {
        int pl=T[p].l,pr=T[p].r;
        if(pl==x&&pr==y) return T[p].sum;
        pushdown(p);
        int mid=(pl+pr)>>1;
        if(y<=mid) return query(p<<1,x,y);
        else if(x>mid) return query(p<<1|1,x,y);
        else return query(p<<1,x,mid)+query(p<<1|1,mid+1,y);
    }
     
    void set(int p,int x,int y,int v)
    {
        int pl=T[p].l,pr=T[p].r;
        if(pl==x&&pr==y)
        {
            T[p].sum=(T[p].r-T[p].l+1)*v;
            T[p].d=v;
            return;
        } 
        pushdown(p);
        int mid=(pl+pr)>>1;
        if(y<=mid) set(p<<1,x,y,v);
        else if(x>mid) set(p<<1|1,x,y,v);
        else
        {
            set(p<<1,x,mid,v);
            set(p<<1|1,mid+1,y,v);
        }
        pushup(p);//
    }
     
    bool check(int x)
    {
        build(1,1,n,x);//建树
        for(int i=1;i<=m;i++)
        {
            int sum=query(1,cl[i],cr[i]);//先求出区间内大于x的个数 
            if(!opt[i])//升序 
            {
                if(sum) set(1,cr[i]-sum+1,cr[i],1);//将1全部放右边
                if(cr[i]-sum>=cl[i]) set(1,cl[i],cr[i]-sum,0); 
            }
            else//降序 
            {
                if(sum) set(1,cl[i],cl[i]+sum-1,1);//将1全部放左边
                if(cl[i]+sum<=cr[i]) set(1,cl[i]+sum,cr[i],0);           
            }
        }
        return query(1,q,q)==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",&opt[i],&cl[i],&cr[i]);
        scanf("%d",&q);
        int l=1,r=n,mid,ans;
        while(l<r)//二分p位置上的值 
        {
            mid=(l+r)>>1;
            if(check(mid)) ans=mid,r=mid;
            else l=mid+1;
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Andriod 简介
    Java 记录日志
    Java 国际化
    Java 正则表达式的使用
    Java 日期、时间类,日期、时间的格式化
    Java Random类、ThreadLocalRandom类
    Java Math类、BigDecimal类、NumberFormat类、浮点数的精确度问题
    Java String类、StringBuilder类、StringBuffer类
    Java System类、RunTime类、Object类、垃圾回收
    span 右浮动折行 解决ie6/7中span右浮动折行问题
  • 原文地址:https://www.cnblogs.com/XYZinc/p/7631445.html
Copyright © 2011-2022 走看看