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 ...
随机推荐
- MySQL — 数据查询语言
目录 1.基础查询 2.条件查询 3.分组查询 4.排序查询 5.分页查询 6.多表查询 6.1.连接查询 6.1.1.内连接 6.1.2.外连接 6.1.3.自连接 6.1.4.联合查询 6.2.子 ...
- Mycat 数据切分 看这一篇就够了
数据切分 数据切分指的是通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库上面,以达到分散单台设备负载的效果. 数据的切分根据其切分规则的类型,可以分为两种切分模式.一种 ...
- You Don't Know JS Yet Book 1 Notes
Get Started - 前言 But let me be clear: I don't think it's possible to ever fully know JS. That's not ...
- SpringCloud项目中接入Nacos作为注册中心
具体demo https://blog.csdn.net/qq_33619378/article/details/95212754 <?xml version="1.0 ...
- 关于web以及浏览器处理预加载有哪些思考?
图片等静态资源在使用之前就提前请求资源使用到的时候能从缓存中加载, 提升用户体验页面展示的依赖关系维护
- String 和StringBuffer、StringBuilder的区别?
Java提供了:String.StringBuffer和StringBuilder,它们都是CharSequence的实现类,都可以作为字符串使用. String代表了字符序列不可变的字符串:而Str ...
- kafka 如何不消费重复数据?比如扣款,我们不能重复的扣?
其实还是得结合业务来思考,我这里给几个思路: 比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入 了,update 一下好吧. 比如你是写 Redis,那没问题了,反正每次都是 s ...
- JS字符串格式化
//字符串格式化String.prototype.format = function () { var values = arguments; return this.replace(/\{(\d+) ...
- 什么是 Callable 和 Future?
Callable 接口类似于 Runnable,从名字就可以看出来了,但是 Runnable 不会返 回结果,并且无法抛出返回结果的异常,而 Callable 功能更强大一些,被线程执 行后,可以返回 ...
- 你对 Spring Boot 有什么了解?
事实上,随着新功能的增加,弹簧变得越来越复杂.如果必须启动新的 spring 项 目,则必须添加构建路径或添加 maven 依赖项,配置应用程序服务器,添加 spring 配置.所以一切都必须从头开始 ...