2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)
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串)的更多相关文章
- [HEOI2016/TJOI2016]排序 线段树+二分
[HEOI2016/TJOI2016]排序 内存限制:256 MiB 时间限制:6000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而 ...
- [Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)
题面 传送门:https://www.luogu.org/problemnew/show/P2824 Solution 这题极其巧妙. 首先,如果直接做m次排序,显然会T得起飞. 注意一点:我们只需要 ...
- 洛谷$P2824\ [HEOI2016/TJOI2016]$ 排序 线段树+二分
正解:线段树+二分 解题报告: 传送门$QwQ$ 昂着题好神噢我$jio$得$QwQQQQQ$,,, 开始看到长得很像之前考试题的亚子,,,然后仔细康康发现不一样昂$kk$,就这里范围是$[1,n]$ ...
- luoguP2824 [HEOI2016/TJOI2016]排序(线段树分裂做法)
题意 所谓线段树分裂其实是本题的在线做法. 考虑如果我们有一个已经排好序的区间的权值线段树,那么就可以通过线段树上二分的方法得到第\(k\)个数是谁. 于是用set维护每个升序/降序区间的左右端点以及 ...
- BZOJ.4552.[HEOI2016/TJOI2016]排序(线段树合并/二分 线段树)
题目链接 对于序列上每一段连续区间的数我们都可以动态开点建一棵值域线段树.初始时就是\(n\)棵. 对于每次操作,我们可以将\([l,r]\)的数分别从之前它所属的若干段区间中分离出来,合并. 对于升 ...
- Luogu P2824 [HEOI2016/TJOI2016]排序 线段树+脑子
只会两个$log$的$qwq$ 我们二分答案:设答案为$ans$,则我们把$a[i]<=ans$全部设成$0$,把$a[i]>ans$全部设成$1$,扔到线段树里,这样区间排序(升序)就是 ...
- day 1 晚上 P2824 [HEOI2016/TJOI2016]排序 线段树
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #inclu ...
- BZOJ4552:[TJOI2016&HEOI2016]排序(线段树,二分)
Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他. 这个难题是这样子的:给出一个1到n的全排列,现在对这 ...
- BZOJ 4552: [Tjoi2016&Heoi2016]排序 线段树 二分
目录 此代码是个假代码,只能糊弄luogu,以后再改,路过大佬也可以帮一下辣 update 10.6 此代码是个假代码,只能糊弄luogu,以后再改,路过大佬也可以帮一下辣 /* //fang zhi ...
随机推荐
- 安装配置Snort和barnyard2
1.安装依赖包 yum install –y gcc flex bison zlib* libpcap* tcpdump gcc-c++ zlib* libdnet libdnet-devel pcr ...
- noi.ac 字符串游戏
题面 Zhangzj和Owaski在玩一个游戏.最开始有一个空的01串,Zhangzj和Owaski轮流进行操作,Zhangzj先走.每次进行操作的人可以在串上任意位置加一个新的字符,由于串是01串, ...
- -std=c++11 编译器设置
range-based 'for' loops are not allowed in C++98 mode
- Java并发机制(2)--synchronized与Lock
本内容整理自:博客园-海 子-java并发编程系列-http://www.cnblogs.com/dolphin0520/category/602384.html 1.基础: 1.什么时候出现线程安全 ...
- 请简述下你在哪些场景下会选择 Kafka?
日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop.HBase.Solr等. 消息系统:解耦和生产者和消费者.缓 ...
- kafka消费组创建和删除原理
0.10.0.0版本的kafka的消费者和消费组已经不在zk上注册节点了,那么消费组是以什么形式存在的呢? 1 入口 看下kafka自带的脚本kafka-consumer-groups.sh,可见脚本 ...
- 如何更愉快地使用em —— 别说你懂CSS相对单位
前段时间试译了Keith J.Grant的CSS好书<CSS in Depth>,其中的第二章<Working with relative units>,书中对relative ...
- 前端进阶(12) - css 的弱化与 js 的强化
css 的弱化与 js 的强化 web 的三要素 html, css, js 在前端组件化的过程中,比如 react.vue 等组件化框架的运用,使 html 的弱化与 js 的强化 成为了一种趋势, ...
- HTML5标签速查
HTML5标签速查,助你快速了解HTML 5. HTML 5新加入的标签以黑体标识,HTML 5不支持的以斜体标识. 标签 描述 <!--...--> 评论 <!DOCTYPE> ...
- python-汇率兑换
按照1美元=6人民币的汇率编写一个美元和人民币的双向兑换程序 输入格式: 输入人民币或美元的金额,人民币格式如:R100,美元格式如:$100 输出格式: 输出经过汇率计算的美元或人民币的金额,格式与 ...