题面

传送门:https://www.luogu.org/problemnew/show/P2824


Solution

这题极其巧妙。

首先,如果直接做m次排序,显然会T得起飞。

注意一点:我们只需要找到一个数。

所以说,我们可以考虑一个绝妙的想法:我们可以用二分答案的方法缩小要找的数的区间。

考虑二分一个值,判定p位置的数排序之后,p位置上的数是否>=mid

如果>=mid,则向右找,否则向左找。

怎么判定p位置的数排序之后是否>=mid呢?

考虑这样做:扫描一遍原数组,>=mid的数赋值为1,<mid的数赋值为0。

这样子,题目就变成了一个01序列排序。

这就很可做了,我们直接线段树维护之即可,我们只需要实现区间查询与区间赋值。

对于一个01区间排序,我们只需要知道这个区间有多少个0,多少个1,然后区间修改即可。

时间复杂度O(m*logn^2)

就酱,这题就可以切掉啦(ノ´▽`)ノ♪


Code

//Luogu  P2824 [HEOI2016/TJOI2016]排序
//Oct,19th,2018
//二分答案缩小范围+线段树妙题
#include<iostream>
#include<cstdio>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=30000+100;
int a[N],w[N];
struct SegmentTree
{
#define lson (now<<1)
#define rson (now<<1|1)
#define mid ((now_l+now_r)>>1)
static const int M=N<<2;
int sum[M][2],lazy[M];
inline void update(int now)
{
sum[now][0]=sum[lson][0]+sum[rson][0];
sum[now][1]=sum[lson][1]+sum[rson][1];
}
inline void pushdown(int now,int now_l,int now_r)
{
if(now_l==now_r)
{
lazy[now]=2;
return;
}
lazy[lson]=lazy[rson]=lazy[now];
sum[lson][lazy[now]]=mid-now_l+1,sum[lson][!lazy[now]]=0;
sum[rson][lazy[now]]=now_r-mid,sum[rson][!lazy[now]]=0;
lazy[now]=2;
}
void Build(int now,int now_l,int now_r)
{
sum[now][0]=sum[now][1]=0;
lazy[now]=2;
if(now_l==now_r)
{
sum[now][w[now_l]]++;
return;
}
Build(lson,now_l,mid);
Build(rson,mid+1,now_r);
update(now);
}
void Change(int L,int R,int x,int now,int now_l,int now_r)
{
if(L>R) return;
if(lazy[now]!=2) pushdown(now,now_l,now_r);
if(now_l>=L and now_r<=R)
{
sum[now][x]=now_r-now_l+1,sum[now][!x]=0;
lazy[now]=x;
return;
}
if(L<=mid) Change(L,R,x,lson,now_l,mid);
if(R>mid) Change(L,R,x,rson,mid+1,now_r);
update(now);
}
int Query(int L,int R,int x,int now,int now_l,int now_r)
{
if(lazy[now]!=2) pushdown(now,now_l,now_r);
if(now_l>=L and now_r<=R)
return sum[now][x];
int ans=0;
if(L<=mid) ans+=Query(L,R,x,lson,now_l,mid);
if(R>mid) ans+=Query(L,R,x,rson,mid+1,now_r);
return ans;
}
#undef lson
#undef rson
#undef mid
}sgt;
struct OP
{
int type,L,R;
}op[N];
int n,m,p;
bool Check(int x)
{
for(int i=1;i<=n;i++)
if(a[i]>=x) w[i]=1;
else w[i]=0;
sgt.Build(1,1,n);
for(int i=1;i<=m;i++)
{
int cnt0=sgt.Query(op[i].L,op[i].R,0,1,1,n),cnt1=op[i].R-op[i].L+1-cnt0;
if(op[i].type==0)
sgt.Change(op[i].L,op[i].L+cnt0-1,0,1,1,n),
sgt.Change(op[i].L+cnt0,op[i].R,1,1,1,n);
else
sgt.Change(op[i].L,op[i].L+cnt1-1,1,1,1,n),
sgt.Change(op[i].L+cnt1,op[i].R,0,1,1,n);
}
if(sgt.Query(p,p,1,1,1,n)==1) return true;
return false;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=m;i++)
op[i].type=read(),op[i].L=read(),op[i].R=read();
p=read(); int L=0,R=n+100,ans=0;
while(L<=R)
{
int mid=(L+R)/2;
if(Check(mid)==true)
ans=max(ans,mid),L=mid+1;
else
R=mid-1;
} printf("%d",ans);
return 0;
}

[Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)的更多相关文章

  1. 洛谷$P2824\ [HEOI2016/TJOI2016]$ 排序 线段树+二分

    正解:线段树+二分 解题报告: 传送门$QwQ$ 昂着题好神噢我$jio$得$QwQQQQQ$,,, 开始看到长得很像之前考试题的亚子,,,然后仔细康康发现不一样昂$kk$,就这里范围是$[1,n]$ ...

  2. Luogu P2824 [HEOI2016/TJOI2016]排序 线段树+脑子

    只会两个$log$的$qwq$ 我们二分答案:设答案为$ans$,则我们把$a[i]<=ans$全部设成$0$,把$a[i]>ans$全部设成$1$,扔到线段树里,这样区间排序(升序)就是 ...

  3. [HEOI2016/TJOI2016]排序 线段树+二分

    [HEOI2016/TJOI2016]排序 内存限制:256 MiB 时间限制:6000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而 ...

  4. day 1 晚上 P2824 [HEOI2016/TJOI2016]排序 线段树

    #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #inclu ...

  5. luogu P2824 [HEOI2016/TJOI2016]排序

    题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行 ...

  6. BZOJ.4552.[HEOI2016/TJOI2016]排序(线段树合并/二分 线段树)

    题目链接 对于序列上每一段连续区间的数我们都可以动态开点建一棵值域线段树.初始时就是\(n\)棵. 对于每次操作,我们可以将\([l,r]\)的数分别从之前它所属的若干段区间中分离出来,合并. 对于升 ...

  7. BZOJ 4552 [Tjoi2016&Heoi2016]排序 ——线段树 二分答案

    听说是BC原题. 好题,二分答案变成01序列,就可以方便的用线段树维护了. 然后就是区间查询和覆盖了. #include <map> #include <cmath> #inc ...

  8. luoguP2824 [HEOI2016/TJOI2016]排序(线段树分裂做法)

    题意 所谓线段树分裂其实是本题的在线做法. 考虑如果我们有一个已经排好序的区间的权值线段树,那么就可以通过线段树上二分的方法得到第\(k\)个数是谁. 于是用set维护每个升序/降序区间的左右端点以及 ...

  9. 「Luogu P2824 [HEOI2016/TJOI2016]排序」

    一道十分神奇的线段树题,做法十分的有趣. 前置芝士 线段树:一个十分基础的数据结构,在这道题中起了至关重要的作用. 一种基于01串的神奇的二分思想:在模拟赛中出现了这道题,可以先去做一下,这样可能有助 ...

随机推荐

  1. 微服务实战系列(十)-网关高可用之中间件Keepalived

    1.场景描述 因为要做网关的高可用,用到了keepalived+nginx,来保证nginx的高可用,如下图: 安装了keepavlived,走了一些弯路,记录下吧,nginx的安装就不多说了,博客已 ...

  2. 在KEIL下查看单片机编程内存使用情况

    原文链接:https://blog.csdn.net/D_azzle/article/details/83410141 截至到目前为止,本人接触单片机也有将近一年的时间.这一年以来也接触过了很具代表性 ...

  3. 《穷查理年鉴》诚实 & 希望 & 勇气 & 失败 & 改变(关于美好)

    诚实 013.自欺是最常见的欺骗. 038.毫无顾忌进行欺骗的人是无所畏惧的. 043.问心无愧者永无所惧. 068.诚实的人从欺诈人手中得到的买卖,我们从争论中得到真理. 134.没有欺骗就没有信任 ...

  4. 为了省钱,我用1天时间把PHP学了!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你在通往架构师的路上吗? 程序员这个行业就像是在不断的打怪升级,突破每一阶段的瓶颈期 ...

  5. Create a cursor from hardcoded array instead of DB

    https://stackoverflow.com/questions/18290864/create-a-cursor-from-hardcoded-array-instead-of-db Crea ...

  6. js 为什么0.1+0.2不等于0.3

    当程序员在使用浮点数进行计算逻辑处理时,不注意,就可能出现问题, 记住,永远不要直接比较俩个浮点的大小 这个属于数字运算中的精度缺失的问题 在0.1 + 0.2这个式子中,0.1和0.2都是近似表示的 ...

  7. day20 Pyhton学习 面向对象-成员

    一.类的成员 class 类名: # 方法 def __init__(self, 参数1, 参数2....): # 属性变量 self.属性1 = 参数1 self.属性2 = 参数2 .... # ...

  8. Shell脚本学习指南笔记(一)

    脚本语言通常是解释型的,这类程序的运行.是由解释器读入程序代码,并将其转换成内部的形式, 再执行,解释器本身是一般的编译型程序. 第一行的开头处使用#!这两个字符,当内核扫描到改行的其余部分,看是否存 ...

  9. 学习python须知,Python基础进阶需掌握哪些知识点?

    Python基础进阶需要掌握哪些知识点?Python将是每个程序员的标配,有编程基础再掌握Python语言对于日后的升职加薪更有利.Python语言简洁利于理解,语法上相对容易能够让开发者更专注于业务 ...

  10. 初学 Python 需要安装哪些软件?

    自动配置.有效求助.协作编程.版本控制.一站式解决 Python 新手练习中的痛点. 痛点 这个学期,我在北得克萨斯大学(University of North Texas)教 INFO 5731: ...