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 ...
随机推荐
- ArcMap连接oracle、oracle配置
服务器:Oracle 11g 客户端:arcgis desktop 10.4.1.oracle 11g 32位客户端 客户端:arcgis server 10.4.1.oracle 11g 64位客户 ...
- mysql(mariadb)安装
mysql(mariadb)安装 前言 MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可. 开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将My ...
- 5月31日 python学习总结 Python中应该使用%还是format来格式化字符串?
%还是format Python中格式化字符串目前有两种阵营:%和format,我们应该选择哪种呢? 自从Python2.6引入了format这个格式化字符串的方法之后,我认为%还是format这根本 ...
- Dubbo 和 Spring Cloud 的区别?
根据微服务架构在各方面的要素,看看 Spring Cloud 和 Dubbo 都提供了哪些支 持. Dubbo Spring Cloud 服务注册中心 Zookeep er Spring Cloud ...
- volatile 有什么用?能否用一句话说明下 volatile 的应用场景?
volatile 保证内存可见性和禁止指令重排. volatile 用于多线程环境下的单次操作(单次读或者单次写).
- docker打包镜像,测试部署
docker基本入门以后,(docker基本入门https://www.cnblogs.com/yangyangming/p/11470926.html)可以试试打包docker镜像与dockerfi ...
- spring bean 容器的生命周期是什么样的?
spring bean 容器的生命周期流程如下: 1.Spring 容器根据配置中的 bean 定义中实例化 bean. 2.Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置. 3 ...
- Servlet之间的关联
- String s = new String(“xyz”);创建了几个字符串对象?
两个对象,一个是静态区的"xyz",一个是用 new 创建在堆上的对象.
- Iterator 和 ListIterator 有什么区别?
1.ListIterator 可以在遍历的时候,调用add()添加元素 2.ListIterator提供了更多的一些方法,如previous().hasPrevious() 等