luoguP2824 [HEOI2016/TJOI2016]排序(二分答案做法)
题意
这题的思路实在巧妙。
首先我们肯定无法对区间进行sort,那么考虑如何使得sort简化。
问:如果给的序列是一个0-1序列,让你区间排序,那么怎么做?
答:建一颗线段树维护sum,求出当前区间中1的数目(query)cnt,之后(以升序排序为例)[l,cnt]都赋值为1,[cnt+1,r]都赋值为0.(赋值没必要更改叶子节点,打个tag就好了)
考虑如何求出答案(神奇):
我们二分答案mid,将序列中小于mid的设为0,大于等于mid的设为1,之后用上述方法完成整个操作,单点查询q位置是否为1.
为什么是正确的:
我们发现如果第q位为1,那么答案必定大于等于mid。
update:2019.6.15
注:代码中必须这么写
if(L>r||R<l) return;
原因
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define sum(p) (tree[p].sum)
#define tag(p) (tree[p].tag)
const int maxn=100010;
int n,m,q,ans;
int a[maxn],op[maxn],ql[maxn],qr[maxn];
struct seg
{
int sum,tag;
}tree[maxn<<2];
void up(int p)
{
sum(p)=sum(ls(p))+sum(rs(p));
}
void down(int p,int l,int r)
{
if(tag(p)<0) return;
int mid=(l+r)>>1;
sum(ls(p))=tag(p)*(mid-l+1);sum(rs(p))=tag(p)*(r-mid);
tag(ls(p))=tag(rs(p))=tag(p);tag(p)=-1;
}
void build(int p,int l,int r,int k)
{
tag(p)=-1;
if(l==r)
{
sum(p)=a[l]>=k;return;
}
int mid=(l+r)>>1;
build(ls(p),l,mid,k);build(rs(p),mid+1,r,k);
up(p);
}
void change(int p,int L,int R,int l,int r,int k)
{
if(L>r||R<l) return;
if(L>=l&&R<=r)
{
sum(p)=(R-L+1)*k;tag(p)=k;return;
}
down(p,L,R);
int mid=(L+R)>>1;
change(ls(p),L,mid,l,r,k);change(rs(p),mid+1,R,l,r,k);
up(p);
}
int query(int p,int L,int R,int l,int r)
{
if(L>r||R<l) return 0;
if(L>=l&&R<=r) return sum(p);
down(p,L,R);
int mid=(L+R)>>1;
return query(ls(p),L,mid,l,r)+query(rs(p),mid+1,R,l,r);
}
bool check(int mid)
{
build(1,1,n,mid);
for(int i=1;i<=m;i++)
{
int cnt=query(1,1,n,ql[i],qr[i]);
if(!op[i])
{
change(1,1,n,qr[i]-cnt+1,qr[i],1);
change(1,1,n,ql[i],qr[i]-cnt,0);
}
else
{
change(1,1,n,ql[i],ql[i]+cnt-1,1);
change(1,1,n,ql[i]+cnt,qr[i],0);
}
}
return query(1,1,n,q,q);
}
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=m;i++) scanf("%lld%lld%lld",&op[i],&ql[i],&qr[i]);
scanf("%lld",&q);
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%lld",ans);
return 0;
}
luoguP2824 [HEOI2016/TJOI2016]排序(二分答案做法)的更多相关文章
- 【BZOJ4552】【HEOI2016】排序 [二分答案][线段树]
排序 Time Limit: 60 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列 ...
- luoguP2824 [HEOI2016/TJOI2016]排序(线段树分裂做法)
题意 所谓线段树分裂其实是本题的在线做法. 考虑如果我们有一个已经排好序的区间的权值线段树,那么就可以通过线段树上二分的方法得到第\(k\)个数是谁. 于是用set维护每个升序/降序区间的左右端点以及 ...
- [Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)
题面 传送门:https://www.luogu.org/problemnew/show/P2824 Solution 这题极其巧妙. 首先,如果直接做m次排序,显然会T得起飞. 注意一点:我们只需要 ...
- [HEOI2016/TJOI2016]排序 线段树+二分
[HEOI2016/TJOI2016]排序 内存限制:256 MiB 时间限制:6000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而 ...
- 2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)
2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串) https://www.luogu.com.cn/problem/P2824 题意: 在 20 ...
- 洛谷 P2824 [HEOI2016/TJOI2016]排序 解题报告
P2824 [HEOI2016/TJOI2016]排序 题意: 有一个长度为\(n\)的1-n的排列\(m\)次操作 \((0,l,r)\)表示序列从\(l\)到\(r\)降序 \((1,l,r)\) ...
- [HEOI2016/TJOI2016] 排序 解题报告(二分答案/线段树分裂合并+set)
题目链接: https://www.luogu.org/problemnew/show/P2824 题目描述: 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在 ...
- BZOJ 4552 [Tjoi2016&Heoi2016]排序 | 二分答案 线段树
题目链接 题面 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这 ...
- [BZOJ4552][TJOI2016&&HEOI2016]排序(二分答案+线段树/线段树分裂与合并)
解法一:二分答案+线段树 首先我们知道,对于一个01序列排序,用线段树维护的话可以做到单次排序复杂度仅为log级别. 这道题只有一个询问,所以离线没有意义,而一个询问让我们很自然的想到二分答案.先二分 ...
随机推荐
- AcWing 45. 之字形打印二叉树
地址 https://www.acwing.com/problem/content/description/43/ 题目描述请实现一个函数按照之字形顺序从上向下打印二叉树. 即第一行按照从左到右的顺序 ...
- C++ 拷贝构造函数 copy ctor & 拷贝赋值函数 copy op=
类中含有 指针类型 的成员变量时,就必须要定义 copy ctor 和 copy op= copy ctor 请见: class Rectangle { public: Rectangle(Rec ...
- 设计模式-State(行为模式)-很好的实现了对象的状态逻辑与动作实现的分类,状态逻辑在State的派生类实现,动作可以放在Context类中实现。
以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Context.h #pragma once class State; class Context { public: C ...
- [ Python入门教程 ] Python生成随机数模块(random)使用方法
1.使用randint(a,b)生成指定范围内的随机整数.randint(a,b)表示从序列range([a,b])中获取一个随机数,包括b. >>> random.randint( ...
- 推荐书单(网课)-人生/编程/Python/机器学习-130本
目录 总计(130本) 一.在读 二.将读 三.已读 非专业书单(77本) 四.已读 专业书单(53本) 五.已看网课(8个) 六.在看网课 一个人如果抱着义务的意识去读书,便不了解读书的艺术.--林 ...
- Java语言入门-第一个HelloWorld程序
1.官网下载Jdk 这里给出官网下载网址:https://www.oracle.com/technetwork/java/javase/downloads . 1.1 打开之后出现如下界面: 1.2选 ...
- EJB学习
EJB:企业级JavaBean(Enterprise JavaBean, EJB)是一个用来构筑企业级应用的服务器端可被管理组件. EJB主要有三种Bean: Session Beans: 会在单个特 ...
- Algorithm: Prime & Euler Function & Productive Function
素数筛 朴素算法 一般来说,可以用试除法判断某一个数是不是素数: bool isPrime(int n) { if(n < 2) return false; for(int i = 2; i & ...
- Ubuntu桌面版安装小记
之前一直是用Ubuntu的桌面版装docker,桌面版本身用起来比较方便,但开销较大,如果建立多个虚拟机就比较费劲了.今天试了一下server版的Ubuntu,发现还是比较方便的,相比桌面版,有如下好 ...
- 谈谈EF Core实现数据库迁移
作为程序员,在日常开发中,记忆犹新的莫过于写代码,升级程序.升级程序包含两部分:一是,对服务程序更新:二是,对数据库结构更新.本篇博文主要介绍数据库结构更新,在对数据库升级时,不知道园友们是否有如下经 ...