题目链接

题面

题目描述

在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]排序 | 二分答案 线段树的更多相关文章

  1. bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 题意: 给你一个1-n的全排列,m次操作,操作由两种:1.将[l,r]升序排序,2 ...

  2. [BZOJ4552][TJOI2016&&HEOI2016]排序(二分答案+线段树/线段树分裂与合并)

    解法一:二分答案+线段树 首先我们知道,对于一个01序列排序,用线段树维护的话可以做到单次排序复杂度仅为log级别. 这道题只有一个询问,所以离线没有意义,而一个询问让我们很自然的想到二分答案.先二分 ...

  3. bzoj 4552 [Tjoi2016&Heoi2016]排序——二分答案

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 二分答案,把 >= mid 的设成1.< mid 的设成0,之后排序就变成 ...

  4. bzoj 4552: [Tjoi2016&Heoi2016]排序——二分+线段树

    Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这 ...

  5. BZOJ 4552: [Tjoi2016&Heoi2016]排序

    4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 579  Solved: 322[Sub ...

  6. BZOJ 4552 [Tjoi2016&Heoi2016]排序 ——线段树 二分答案

    听说是BC原题. 好题,二分答案变成01序列,就可以方便的用线段树维护了. 然后就是区间查询和覆盖了. #include <map> #include <cmath> #inc ...

  7. BZOJ 4552: [Tjoi2016&Heoi2016]排序 线段树 二分

    目录 此代码是个假代码,只能糊弄luogu,以后再改,路过大佬也可以帮一下辣 update 10.6 此代码是个假代码,只能糊弄luogu,以后再改,路过大佬也可以帮一下辣 /* //fang zhi ...

  8. bzoj 4552: [Tjoi2016&Heoi2016]排序【二分+线段树】

    二分值mid,然后把>=mid的赋值为1,其他赋值为0,每次排序就是算出区间内01的个数,然后分别把0和1放到连续的一段内,这些都可以用线段树来维护 二分的判断条件是操作完之后q位置上是否为1 ...

  9. BZOJ 4552 [Tjoi2016&Heoi2016]排序 线段树的分裂和合并

    https://www.lydsy.com/JudgeOnline/problem.php?id=4552 https://blog.csdn.net/zawedx/article/details/5 ...

随机推荐

  1. C#基础巩固(1)-多态+简单工厂

    多态 如果要简要的描述多态的话,我个人是这样理解的:通过继承,父类定义方法,具休的实现由子类进行. 01代码 //父类 class Person { public virtual void skill ...

  2. 机器学习sklearn19.0聚类算法——Kmeans算法

    一.关于聚类及相似度.距离的知识点 二.k-means算法思想与流程 三.sklearn中对于kmeans算法的参数 四.代码示例以及应用的知识点简介 (1)make_blobs:聚类数据生成器 sk ...

  3. 《Head First 设计模式》例子的C++实现(1 策略模式)

    最近在学习设计模式,用的是 <Head First 设计模式>这本书.感觉这本书写的还是很不错的,深入浅出的介绍了各种常用的设计模式.唯一有点不方便的地方是这本书的例子全都是用的 Java ...

  4. 机器学习 第四篇:OLS回归分析

    变量之间存在着相关关系,比如,人的身高和体重之间存在着关系,一般来说,人高一些,体重要重一些,身高和体重之间存在的是不确定性的相关关系.回归分析是研究相关关系的一种数学工具,它能帮助我们从一个变量的取 ...

  5. cgroup.conf系统初始配置

    # Slurm cgroup support configuration file # # See man slurm.conf and man cgroup.conf for further # i ...

  6. 分布式监控系统Zabbix-3.0.3-完整安装记录 - 添加shell脚本监控

    对公司的jira访问状态进行监控,当访问状态返回值是200的时候,脚本执行结果为1:其他访问状态返回值,脚本执行结果是0.然后将该脚本放在zabbix进行监控,当非200状态时发出报警.jira访问状 ...

  7. Redis常见问题和解决办法梳理

    =============Redis主从复制问题和解决办法 ================= 一.Redis主从复制读写分离问题 1)数据复制的延迟读写分离时,master会异步的将数据复制到sla ...

  8. <构建之法>13-17

    13章软件测试. 从基本名词到软件测试的分类方法,啃完这15页书,至少对与软件测试的理解程度不是停留在以前的层次(让用户使用,然后提出碰到什么问题) 测试不是那么简单就阐述的完全.测试按测试目的分类可 ...

  9. 业务-----添加Service常用逻辑

    1.参数不能为空 /** * 添加人员时判断是否字段全部传值 * @param request * @return */ private Boolean checkClientByCols(Clien ...

  10. Linux curl 一例

    root@PC-RENGUOQIANG:~# curl http://kermit:kermit@192.168.66.182:8080/activiti-rest/service/repositor ...