2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)

https://www.luogu.com.cn/problem/P2824

题意:

在 2016 年,佳媛姐姐喜欢上了数字序列。因而她经常研究关于序列的一些奇奇怪怪的问题,现在她在研究一个难题,需要你来帮助她。

这个难题是这样子的:给出一个 1 到 n 的排列,现在对这个排列序列进行 m 次局部排序,排序分为两种:

  • 0 l r 表示将区间 \([l,r]\) 的数字升序排序
  • 1 l r 表示将区间 \([l,r]\) 的数字降序排序

注意,这里是对下标在区间 \([l,r]\) 内的数排序。

最后询问第 \(q\) 位置上的数字。

分析:

先二分答案二分出位置 \(p\) 上可能的结果 \(maxn\) ,把大于等于 \(maxn\) 的数全部标成 \(1\) ,否则标成 \(0\) 。这样对于一个 \(01\) 串进行升序或降序排序就是把一个区间分成两半,一半全部区间修改 \(1\) ,另一半修改成 \(0\) 。对于位置 \(p\) ,如果这个节点上是 \(1\) ,那么就能肯定这个数大于等于 \(maxn\) ,不断二分,直至确定这个数究竟是多少。

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ls (x<<1)
#define rs (x<<1)|1
using namespace std; const int N=1e5+10;
int n,m,val[N],p,a[N];
struct node{
int len,sum,lazy;
}t[N<<3];
struct nodei{
int op,l,r;
}q[N]; inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline void update(int x){
t[x].sum=t[ls].sum+t[rs].sum;
}
inline void pre_pushdown(int x,int flag){
if(flag==1)t[x].sum=t[x].len;
else t[x].sum=0;
}
inline void pushdown(int x){
if(t[x].lazy==-1)return ;
t[ls].lazy=t[rs].lazy=t[x].lazy;
pre_pushdown(ls,t[x].lazy);
pre_pushdown(rs,t[x].lazy);
t[x].lazy=-1;
}
inline void build(int x,int l,int r,int maxn){
t[x].lazy=-1;t[x].len=r-l+1;
if(l==r)return (void)(t[x].sum=val[l]>=maxn);
int mid=(l+r)>>1;
build(ls,l,mid,maxn);
build(rs,mid+1,r,maxn);
update(x);
}
inline int query(int x,int l,int r,int L,int R){
if(l>R||r<L)return 0;
if(l>=L&&r<=R)return t[x].sum;
pushdown(x);
int mid=(l+r)>>1;
int ans=0;
if(L<=mid)ans+=query(ls,l,mid,L,R);
if(R>mid)ans+=query(rs,mid+1,r,L,R);
update(x);
return ans;
}
inline void change(int x,int l,int r,int L,int R,int k){
if(l>R||r<L)return ;
if(l>=L&&r<=R){
t[x].lazy=k;
pre_pushdown(x,k);
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)change(ls,l,mid,L,R,k);
if(R>mid)change(rs,mid+1,r,L,R,k);
update(x);
}
inline void find(){
for(int i=1;i<=n;i++)cout<<query(1,1,n,i,i)<<" ";cout<<endl;
}
inline bool check(int maxn){
build(1,1,n,maxn);
//cout<<"maxn "<<maxn<<endl;
//find();
for(int i=1;i<=m;i++){
int len=query(1,1,n,q[i].l,q[i].r);
if(q[i].op==0){
change(1,1,n,q[i].r-len+1,q[i].r,1);
if(q[i].r-len>=q[i].l)change(1,1,n,q[i].l,q[i].r-len,0);
}else{
change(1,1,n,q[i].l,q[i].l+len-1,1);
if(q[i].l+len<=q[i].r)change(1,1,n,q[i].l+len,q[i].r,0);
}
//cout<<"op "<<q[i].op<<" l "<<q[i].l<<" r "<<q[i].r<<" len "<<len<<endl;
//find();
}
if(query(1,1,n,p,p))return true;
else return false;
}
inline void erfen(){
int L=1,R=n,mid,ans=0;
//sort(a+1,a+n+1);
while(L<=R){
mid=(L+R)>>1;
//cout<<"L "<<L<<" R "<<R<<" mid "<<mid<<endl;
if(check(mid))L=mid+1,ans=mid;
else R=mid-1;
}
cout<<ans;
} int main(){
n=read();m=read();
for(int i=1;i<=n;i++)val[i]=a[i]=read();
for(int i=1;i<=m;i++)q[i].op=read(),q[i].l=read(),q[i].r=read();
p=read();
erfen();
return 0;
}

2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)的更多相关文章

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

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

  2. [Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)

    题面 传送门:https://www.luogu.org/problemnew/show/P2824 Solution 这题极其巧妙. 首先,如果直接做m次排序,显然会T得起飞. 注意一点:我们只需要 ...

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

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

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

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

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

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

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

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

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

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

  8. BZOJ4552:[TJOI2016&HEOI2016]排序(线段树,二分)

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

  9. BZOJ 4552: [Tjoi2016&Heoi2016]排序 线段树 二分

    目录 此代码是个假代码,只能糊弄luogu,以后再改,路过大佬也可以帮一下辣 update 10.6 此代码是个假代码,只能糊弄luogu,以后再改,路过大佬也可以帮一下辣 /* //fang zhi ...

随机推荐

  1. 使用systemd-analyze 工具来分析各个服务进程的启动性能

    systemd-analyze是一个分析启动性能的工具,用于分析启动时服务时间消耗.默认显示启动是内核和用户空间的消耗时间:使用systemd-analyze plot > boot.svg生成 ...

  2. 3、Lambda表达式

    Lambda表达式 Lambda表达式(lambda expression),是一种匿名函数,即没有函数名的函数. Lambda表达式不仅在C#中使用,在Java.Phtyon.C++ 中都有使用. ...

  3. 航模电池平衡头接线,1S-6S原理图

    1-4S平衡头接线 S数代表几级锂电池串联,比如3S代表串联了3级,所以总电压为3*3.7V=11.4V.(每一级可能是多个电芯并联) 图源:百度贴吧 图源:5imx论坛 3S电池示例 B6充电器

  4. Prometheus由于时间不同步导致数据不显示

    原文链接:Prometheus由于时间不同步导致数据不显示 问题 部署 prometheus 后,访问前端界面发现: 这是由于你windows机器与部署prometheus服务器的时间不同步导致的. ...

  5. Spring Authorization Server 0.2.3发布,放出联合身份DEMO

    很快啊Spring Authorization Server又发新版本了,现在的版本是0.2.3.本次都有什么改动呢?我们来了解一下. 0.2.3版本特性 本次更新的新特性不少. 为公开客户端提供默认 ...

  6. Java基础 (下)

    泛型 Java 泛型了解么?什么是类型擦除?介绍一下常用的通配符? Java 泛型(generics) 是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时 ...

  7. Java8 HashMap扩容时为什么不需要重新hash

    技巧: 与&操作   和   与 n 如8 与,为0  则位置不变 https://blog.csdn.net/zlp1992/article/details/104376309 java8在 ...

  8. 使用Pycharm获取Resources目录里的内容

    def get_resource_path(path: str) -> str: """\ 获取Resources目录里的资源 :param path: :retu ...

  9. 详细描述一下 Elasticsearch 更新和删除文档的过程?

    1.删除和更新也都是写操作,但是 Elasticsearch 中的文档是不可变的,因此不 能被删除或者改动以展示其变更: 2.磁盘上的每个段都有一个相应的.del 文件.当删除请求发送后,文档并没有真 ...

  10. c语言思维导图