排序

Time Limit: 60 Sec  Memory Limit: 256 MB
[Submit][Status][Discuss]

Description

  在2016年,佳媛姐姐喜欢上了数字序列。
  因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。
  这个难题是这样子的:
  给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:
    1: (0,l,r)表示将区间[l,r]的数字升序排序
    2: (1,l,r)表示将区间[l,r]的数字降序排序
  最后询问第q位置上的数字。

Input

  输入数据的第一行为两个整数n和m。
  n表示序列的长度,m表示局部排序的次数。
  第二行为n个整数,表示1到n的一个全排列。
  接下来输入m行,每一行有三个整数op, l, r,
   op为0代表升序排序,op为1代表降序排序, l, r 表示排序的区间。
  最后输入一个整数q,q表示排序完之后询问的位置。

Output

  输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

Sample Input

  6 3
  1 6 2 5 3 4
  0 1 4
  1 3 6
  0 2 4
  3

Sample Output

  5

HINT

  1 <= n <= 10^5,1 <= m <= 10^5, 1 <= q <= n。

Solution

  我们先考虑如果权值很小的话怎么做,显然可以对每个权值开一个线段树维护在哪些位置出现过。

  那么排序显然就是覆盖连续的一段。只要知道某一区间有几个这个权值即可。

  但是这样显然是过不了的,于是我们考虑二分答案,把val >= mid的设为1,其余的设为0

  这样就把权值变成了0/1,那么显然我们按照以上操作,如果Q位置上是1说明mid<=Ans还可以更大一点否则说明mid>Ans

  只要支持区间求和以及区间覆盖0/1即可。

Code

 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long s64; const int ONE = ;
const int MOD = 1e9 + ; int get()
{
int res = , Q = ; char c;
while( (c = getchar()) < || c > )
if(c == '-') Q = -;
if(Q) res = c - ;
while( (c = getchar()) >= && c <= )
res = res * + c - ;
return res * Q;
} int n, m, Q;
int a[ONE];
int res, now; struct power
{
struct point
{
int val, tag;
}Node[ONE]; void Build(int i, int l, int r)
{
Node[i].tag = -;
if(l == r) return;
int mid = l + r >> ;
Build(i << , l, mid);
Build(i << | , mid + , r);
} int pushdown(int i, int l, int r)
{
int mid = l + r >> ;
if(Node[i].tag != -)
{
Node[i << ].tag = Node[i].tag;
Node[i << ].val = Node[i].tag * (mid - l + );
Node[i << | ].tag = Node[i].tag;
Node[i << | ].val = Node[i].tag * (r - (mid + ) + );
Node[i].tag = -;
}
} void Update(int i, int l, int r, int L, int R, int x)
{
if(L > R) return;
if(L <= l && r <= R)
{
Node[i].tag = x;
Node[i].val = x * (r - l + );
return;
}
pushdown(i, l, r);
int mid = l + r >> ;
if(L <= mid) Update(i << , l, mid, L, R, x);
if(mid + <= R) Update(i << | , mid + , r, L, R, x);
Node[i].val = Node[i << ].val + Node[i << | ].val;
} void Query(int i, int l, int r, int L, int R)
{
if(L > R) return;
if(L <= l && r <= R)
{
res += Node[i].val;
return;
}
pushdown(i, l, r);
int mid = l + r >> ;
if(L <= mid) Query(i << , l, mid, L, R);
if(mid + <= R) Query(i << | , mid + , r, L, R);
}
}C[]; struct operate
{
int l, r, x;
}oper[ONE]; void Modify(int id, int Left, int Right)
{
res = ;
C[id].Query(, , n, Left, Right);
C[id].Update(, , n, Left, Right, );
C[id].Update(, , n, now, now + res - , );
now += res;
} int Check(int mid)
{
for(int i = ; i <= ; i++)
C[i].Node[].tag = ; for(int i = ; i <= n; i++)
C[a[i] >= mid].Update(, , n, i, i, ); for(int i = ; i <= m; i++)
{
now = oper[i].l;
if(oper[i].x == ) for(int id = ; id <= ; id++) Modify(id, oper[i].l, oper[i].r);
if(oper[i].x == ) for(int id = ; id >= ; id--) Modify(id, oper[i].l, oper[i].r);
} res = , C[].Query(, , n, Q, Q);
return res;
} int main()
{
n = get(); m = get();
for(int i = ; i <= n; i++)
a[i] = get();
for(int i = ; i <= m; i++)
oper[i].x = get(), oper[i].l = get(), oper[i].r = get(); Q = get();
int l = , r = n;
while(l < r - )
{
int mid = l + r >> ;
if(Check(mid)) l = mid;
else r = mid;
} if(Check(r)) printf("%d", r);
else printf("%d", l);
}

  

【BZOJ4552】【HEOI2016】排序 [二分答案][线段树]的更多相关文章

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

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

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

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

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

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

  4. HDU 5649 DZY Loves Sorting(二分答案+线段树/线段树合并+线段树分割)

    题意 一个 \(1\) 到 \(n\) 的全排列,\(m\) 种操作,每次将一段区间 \([l,r]\) 按升序或降序排列,求 \(m\) 次操作后的第 \(k\) 位. \(1 \leq n \le ...

  5. [BZOJ4552][Tjoi2016&Heoi2016]排序(二分答案+线段树)

    二分答案mid,将>=mid的设为1,<mid的设为0,这样排序就变成了区间修改的操作,维护一下区间和即可 然后询问第q个位置的值,为1说明>=mid,以上 时间复杂度O(nlog2 ...

  6. [HEOI2016/TJOI2016] 排序 解题报告(二分答案/线段树分裂合并+set)

    题目链接: https://www.luogu.org/problemnew/show/P2824 题目描述: 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在 ...

  7. 【Luogu】P2824排序(二分答案+线段树排序)

    题目链接 震惊!两个线段树和一个线段树竟是50分的差距! 本题可以使用二分答案,二分那个位置上最后是什么数.怎么验证呢? 把原序列改变,大于等于mid的全部变成1,小于mid的全部变成0,之后线段树排 ...

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

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

  9. YbtOJ#463-序列划分【二分答案,线段树,dp】

    正题 题目链接:https://www.ybtoj.com.cn/problem/463 题目大意 给出长度为\(n\)的序列\(A,B\).要求划分成若干段满足 对于任何\(i<j\),若\( ...

随机推荐

  1. lintcode-248-统计比给定整数小的数的个数

    248-统计比给定整数小的数的个数 给定一个整数数组 (下标由 0 到 n-1,其中 n 表示数组的规模,数值范围由 0 到 10000),以及一个 查询列表.对于每一个查询,将会给你一个整数,请你返 ...

  2. C++ Primer Plus学习:第十章

    过程性编程和面向对象编程 面向对象编程(OOP)的特性: 抽象 封装和数据隐藏 多态 继承 代码的可重用性 抽象和类 类是一种将抽象转化为用户定义类型的C++工具,它将数据表示和操纵数据的方法合成一个 ...

  3. WCF RestFull提交数据超出限额解决方法

    最近在使用wcf restfull时出现了超大数据提交出错的问题. 服务端会返回错误:服务器处理请求时遇到错误.有关构造有效服务请求的内容,请参阅服务帮助页.异常消息为“反序列化对象 属于类型 Yes ...

  4. UML之Enterprise Architect使用

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:UML之Enterprise Architect使用     本文地址:http://tech ...

  5. IDEA换行CRLF, LF, CR的解释和默认设置

    在window下开发有一个大坑,就是换行默认是CRLF,也就是回车换行,但是Linux下只有换行LF,这样代码提交后,会出现编译问题,所以最好的办法是在IDEA下设置默认为LF. 首先我们先介绍CRL ...

  6. 第190天:js---String常用属性和方法(最全)

    String常用属性和方法 一.string对象构造函数 /*string对象构造函数*/ console.log('字符串即对象');//字符串即对象 //传统方式 - 背后会自动将其转换成对象 / ...

  7. HttpHandler与HttpModule的理解与应用

    问题1:什么是HttpHandler? 问题2:什么是HttpModule? 问题3:什么时候应该使用HttpHandler什么时候使用HttpModule? 答案1:HttpHandler,Http ...

  8. codeforces 1027 E. Inverse coloring (DP)

    E. Inverse Coloring time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  9. Android四大组件之Intent(续)

  10. VS中碰到的问题

    1.调试的时候,语句已经注释掉了,但是在执行的时候还是运行了(或者某些变量值改变后,程序依然用的之前数据). 右键解决方案-->清理,然后重新生成.