BZOJ 4552 [Tjoi2016&Heoi2016]排序 | 二分答案 线段树
题目链接
题面
题目描述
在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:
1:(0,l,r)表示将区间[l,r]的数字升序排序
2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q位置上的数字。输入输出格式
输入格式:
输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。
1 <= n, m <= 10^5第二行为n个整数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序排序, l, r 表示排序的区间。
最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5,1 <= m <= 10^5输出格式:
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。
题解
这道题好有趣 = =
正解居然是二分答案!
因为最后要询问的只有一个位置,所以直接二分这个位置上的数。
然后修改一下原数组——原数组中比二分的答案大的数都改为1, 小于等于的都改为0。
然后用线段树模拟整个排序过程。把一个01序列的区间排序是很简单的——数出区间内有多少个1, 然后(如果是顺序排序)把右面对应的几个改成1, 剩下的改成0。
模拟执行一遍之后就可以知道实际上排完序后询问位置上的数应该比你二分的答案大还是小了,继续二分即可。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#define space putchar(' ')
#define enter putchar('\n')
typedef long long ll;
using namespace std;
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 100005;
int n, m, a[N], val[N], pos, op[N], ql[N], qr[N];
int data[4*N];
bool lazy[4*N], tag[4*N];
void build(int k, int l, int r){
tag[k] = 0;
if(l == r) return (void)(data[k] = val[l]);
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
data[k] = data[k << 1] + data[k << 1 | 1];
}
void pushdown(int k, int l, int r){
if(!tag[k]) return;
int mid = (l + r) >> 1;
data[k << 1] = lazy[k] * (mid - l + 1);
data[k << 1 | 1] = lazy[k] * (r - mid);
lazy[k << 1] = lazy[k << 1 | 1] = lazy[k];
tag[k << 1] = tag[k << 1 | 1] = 1;
tag[k] = 0;
}
void change(int k, int l, int r, int ql, int qr, int x){
if(ql <= l && qr >= r) return (void)(data[k] = x * (r - l + 1), lazy[k] = x, tag[k] = 1);
pushdown(k, l, r);
int mid = (l + r) >> 1;
if(ql <= mid) change(k << 1, l, mid, ql, qr, x);
if(qr > mid) change(k << 1 | 1, mid + 1, r, ql, qr, x);
data[k] = data[k << 1] + data[k << 1 | 1];
}
int query(int k, int l, int r, int ql, int qr){
if(ql <= l && qr >= r) return data[k];
pushdown(k, l, r);
int mid = (l + r) >> 1, ret = 0;
if(ql <= mid) ret += query(k << 1, l, mid, ql, qr);
if(qr > mid) ret += query(k << 1 | 1, mid + 1, r, ql, qr);
return ret;
}
int main(){
read(n), read(m);
for(int i = 1; i <= n; i++) read(a[i]);
for(int i = 1; i <= m; i++)
read(op[i]), read(ql[i]), read(qr[i]);
read(pos);
int l = 1, r = n, mid;
while(l < r){
mid = (l + r) >> 1;
for(int i = 1; i <= n; i++)
val[i] = a[i] > mid;
build(1, 1, n);
for(int i = 1; i <= m; i++){
int cnt = query(1, 1, n, ql[i], qr[i]);
if(op[i]){
if(cnt) change(1, 1, n, ql[i], ql[i] + cnt - 1, 1);
if(ql[i] + cnt <= qr[i]) change(1, 1, n, ql[i] + cnt, qr[i], 0);
}
else{
if(cnt) change(1, 1, n, qr[i] - cnt + 1, qr[i], 1);
if(qr[i] - cnt >= ql[i]) change(1, 1, n, ql[i], qr[i] - cnt, 0);
}
}
if(query(1, 1, n, pos, pos)) l = mid + 1;
else r = mid;
}
write(l), enter;
return 0;
}
BZOJ 4552 [Tjoi2016&Heoi2016]排序 | 二分答案 线段树的更多相关文章
- bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 题意: 给你一个1-n的全排列,m次操作,操作由两种:1.将[l,r]升序排序,2 ...
- [BZOJ4552][TJOI2016&&HEOI2016]排序(二分答案+线段树/线段树分裂与合并)
解法一:二分答案+线段树 首先我们知道,对于一个01序列排序,用线段树维护的话可以做到单次排序复杂度仅为log级别. 这道题只有一个询问,所以离线没有意义,而一个询问让我们很自然的想到二分答案.先二分 ...
- bzoj 4552 [Tjoi2016&Heoi2016]排序——二分答案
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 二分答案,把 >= mid 的设成1.< mid 的设成0,之后排序就变成 ...
- bzoj 4552: [Tjoi2016&Heoi2016]排序——二分+线段树
Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这 ...
- BZOJ 4552: [Tjoi2016&Heoi2016]排序
4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 579 Solved: 322[Sub ...
- BZOJ 4552 [Tjoi2016&Heoi2016]排序 ——线段树 二分答案
听说是BC原题. 好题,二分答案变成01序列,就可以方便的用线段树维护了. 然后就是区间查询和覆盖了. #include <map> #include <cmath> #inc ...
- BZOJ 4552: [Tjoi2016&Heoi2016]排序 线段树 二分
目录 此代码是个假代码,只能糊弄luogu,以后再改,路过大佬也可以帮一下辣 update 10.6 此代码是个假代码,只能糊弄luogu,以后再改,路过大佬也可以帮一下辣 /* //fang zhi ...
- bzoj 4552: [Tjoi2016&Heoi2016]排序【二分+线段树】
二分值mid,然后把>=mid的赋值为1,其他赋值为0,每次排序就是算出区间内01的个数,然后分别把0和1放到连续的一段内,这些都可以用线段树来维护 二分的判断条件是操作完之后q位置上是否为1 ...
- BZOJ 4552 [Tjoi2016&Heoi2016]排序 线段树的分裂和合并
https://www.lydsy.com/JudgeOnline/problem.php?id=4552 https://blog.csdn.net/zawedx/article/details/5 ...
随机推荐
- c# create html table test
string html = "<html><head><title>44444444</title>"; html += @&quo ...
- maven 通过 pom.xml 指定java编译版本
<!-- 给maven项目指定编译版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> ...
- C#编写WINNT服务,随便解决安卓开发遇到的5037被众多程序无节操占用的问题
需求分析: 最近重新开始学习安卓开发,好久不用的ADT集成开发环境频繁遇到不能在仿真机和真机上调试的问题,也就是本人另一篇博文描述的ADB(Android Debug Bridge)监控的5037被金 ...
- 使用IntelliJ IDEA开发SpringMVC网站(二)框架配置
原文:使用IntelliJ IDEA开发SpringMVC网站(二)框架配置 摘要 讲解如何配置SpringMVC框架xml,以及如何在Tomcat中运行 目录[-] 文章已针对IDEA 15做了一定 ...
- C. Meme Problem
链接 [http://codeforces.com/contest/1076/problem/C] 题意 a+b=d and a⋅b=d. 计算出a和b 分析 ab=a(d-a)=d aa-ad+d= ...
- 附加题(一)——interesting的抄袭现象
这次的作业很有意思,是让我们搜索抄袭的同学的个人总结,并让我们列出链接,时间,作者及原因.其实我不是很能理解,抄袭现象是可耻的不受推崇的这是无可厚非,但是为什么要求我们大部分没有抄袭的同学去探究抄袭同 ...
- sql 语句的先后执行顺序
例:查询语句中select from where group by having order by的执行顺序 一般以为会按照逻辑思维执行,为: 查询中用到的关键词主要包含六个,并且他们的顺序依次为 ...
- warning C4996: 'strcpy': This function or variable may be unsafe.
mkdir 写成 _mkdir strcpy 写成为 strcpy_s 或是在项目处右击-->属性-->C/C++-->预处理器-->在预处理器定义后添加";_CR ...
- 使用github的感想
github的仓库链接:https://github.com/liyan941016/test github是一个基于git的代码托管平台,要想使用github第一步就要注册账户,然后要创建一个仓库 ...
- githup地址
githup地址:https://github.com/caowenjing/test.git