题目大意

  给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:(0,l,r)表示将区间[l,r]的数字升序排序;(1,l,r)表示将区间[l,r]的数字降序排序。最后询问第q位置上的数字。n<=30000。

题解

  关键词:反演。

  我们假设最后q位置上的值为val。此时我们对整个序列进行排序...我们发现除了val外,其它点之间的顺序并不重要,只有其他点与val的相对大小才有意义。所以我们将原序列中位置上的值小于val的的值设为0,大于等于的设为1,整个序列上每个点的值表示的就是序列上的原值与val的大小关系。这样对01值排序用覆盖式的线段树来进行排序过程最方便了(具体看代码中的Sort)。

  此时q位置上的值如果是0,则说明当前的val比答案大;若此时q位置上的值是1,则说明当前的val小于或等于答案。也就是说,val越大,最后q位上的值越有可能是0,val越小,q位上的值越有可能是1。因此我们可以用UpperBound二分得出答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace std; const int MAX_N = 30010, MAX_NODE = MAX_N * 4, MAX_OP = 30010;
int OrgData[MAX_N];
int N, TotOp, P; struct RangeTree
{
private: struct Node
{
int Sum, Cover;
}_nodes[MAX_NODE];
int N; void PushDown(int cur, int l, int r)
{
if (_nodes[cur].Cover >= 0)
{
_nodes[cur * 2].Cover = _nodes[cur].Cover;
_nodes[cur * 2 + 1].Cover = _nodes[cur].Cover; int mid = (l + r) / 2;
_nodes[cur * 2].Sum = _nodes[cur].Cover * (mid - l + 1);
_nodes[cur * 2 + 1].Sum = _nodes[cur].Cover * (r - mid); _nodes[cur].Cover = -1;
}
} void PullUp(int cur)
{
_nodes[cur].Sum = _nodes[cur * 2].Sum + _nodes[cur * 2 + 1].Sum;
} void Update(int cur, int al, int ar, int sl, int sr, int cover)
{
assert(al <= sr && ar >= sl && sl <= sr);
if (al <= sl && sr <= ar)
{
_nodes[cur].Cover = cover;
_nodes[cur].Sum = cover * (sr - sl + 1);
return;
}
PushDown(cur, sl, sr);
int mid = (sl + sr) / 2;
if (al <= mid)
Update(cur * 2, al, ar, sl, mid, cover);
if (ar > mid)
Update(cur * 2 + 1, al, ar, mid + 1, sr, cover);
PullUp(cur);
} int Query(int cur, int al, int ar, int sl, int sr)
{
assert(al <= sr && ar >= sl && sl <= sr);
if (al <= sl && sr <= ar)
return _nodes[cur].Sum;
PushDown(cur, sl, sr);
int mid = (sl + sr) / 2, ans = 0;
if (al <= mid)
ans += Query(cur * 2, al, ar, sl, mid);
if (ar > mid)
ans += Query(cur * 2 + 1, al, ar, mid + 1, sr);
PullUp(cur);
return ans;
} void InitBuild(int cur, int sl, int sr, int *a)
{
if (sl == sr)
{
_nodes[cur].Sum = a[sl];
_nodes[cur].Cover = -1;
return;
}
int mid = (sl + sr) / 2;
InitBuild(cur * 2, sl, mid, a);
InitBuild(cur * 2 + 1, mid + 1, sr, a);
_nodes[cur].Cover = -1;
PullUp(cur);
} public: void Init(int n, int *a)
{
N = n;
InitBuild(1, 1, N, a);
} void Update(int l, int r, int cover)
{
if (l > r)
return;
Update(1, l, r, 1, N, cover);
} int Query(int l, int r)
{
return Query(1, l, r, 1, N);
}
}g; struct Oper//operation
{
int L, R;
bool IsUp; Oper(){}
Oper(int l, int r, int isUp):L(l),R(r),IsUp(isUp){}
}_ops[MAX_OP]; void Sort(Oper op)
{
int sum1 = g.Query(op.L, op.R);
if (op.IsUp)
{
g.Update(op.R - sum1 + 1, op.R, 1);
g.Update(op.L, op.R - sum1, 0);
}
else
{
g.Update(op.L, op.L + sum1 - 1, 1);
g.Update(op.L + sum1, op.R, 0);
}
} bool AnsNotLesser(int val)
{
static int a[MAX_N];
for (int i = 1; i <= N; i++)
a[i] = (OrgData[i] >= val);
g.Init(N, a); for (int i = 1; i <= TotOp; i++)
Sort(_ops[i]);
return g.Query(P, P) == 1;
} int UpperBound(int l, int r, bool(*InRange)(int))
{
while (l < r)
{
int mid = (l + r + 1) / 2;
if (InRange(mid))
l = mid;
else
r = mid - 1;
}
return l;
} int main()
{
scanf("%d%d", &N, &TotOp);
for (int i = 1; i <= N; i++)
scanf("%d", OrgData + i);
for (int i = 1; i <= TotOp; i++)
{
int l, r, isDown;
scanf("%d%d%d", &isDown, &l, &r);
_ops[i] = Oper(l, r, !isDown);
}
scanf("%d", &P);
printf("%d\n", UpperBound(1, N, AnsNotLesser));
return 0;
}

  

luogu2828 [HEOI2016/TJOI2016]排序的更多相关文章

  1. 洛谷 P2824 [HEOI2016/TJOI2016]排序 解题报告

    P2824 [HEOI2016/TJOI2016]排序 题意: 有一个长度为\(n\)的1-n的排列\(m\)次操作 \((0,l,r)\)表示序列从\(l\)到\(r\)降序 \((1,l,r)\) ...

  2. [HEOI2016/TJOI2016]排序 线段树+二分

    [HEOI2016/TJOI2016]排序 内存限制:256 MiB 时间限制:6000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而 ...

  3. [Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)

    题面 传送门:https://www.luogu.org/problemnew/show/P2824 Solution 这题极其巧妙. 首先,如果直接做m次排序,显然会T得起飞. 注意一点:我们只需要 ...

  4. 2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)

    2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串) https://www.luogu.com.cn/problem/P2824 题意: 在 20 ...

  5. [HEOI2016&TJOI2016] 排序(线段树)

    4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2703  Solved: 1386[S ...

  6. [HEOI2016/TJOI2016]排序

    嘟嘟嘟 首先这题的暴力是十分好写的,而且据说能得不少分. 正解写起来不难,就是不太好想. 根据做题经验,我想到了给这个序列转化成01序列,但是接下来我就不会了.还是看了题解. 因为查询只有一个数,所以 ...

  7. 【线段树合并】【P2824】 [HEOI2016/TJOI2016]排序

    Description 给定一个长度为 \(n\) 的排列,有 \(m\) 次操作,每次选取一段局部进行升序或降序排序,问你一波操作后某个位置上的数字是几 Hint \(1~\leq~n,~m~\le ...

  8. 【[HEOI2016/TJOI2016]排序】

    巧妙思路题 有一个重要的思想就是把大于某一个数的数都变成\(1\),小于这个数的都变成\(0\),这个只有\(0\)和\(1\)的序列就很好处理了 由于我们只需要在最后求出一个位置上是什么数就可以了, ...

  9. BZOJ4552:[HEOI2016/TJOI2016]排序——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4552 https://www.luogu.org/problemnew/show/P2824 在2 ...

随机推荐

  1. CSS布局——三栏布局

    说到三栏布局,很多都会提到圣杯布局和双飞翼布局这两个经典的三栏布局方式.于是,我在网上搜了一些相关资料,阅读并跟着代码敲了一遍,发现在处理三栏布局上,他们采用的都是两边栏固定,中间栏自适应的策略.在处 ...

  2. jQuery——尺寸位置

    获取宽:$(".box").width() 设置宽:$(".box").width(200) 获取高:$(".box").height() ...

  3. CSS——半透明

    1.opacity:不仅背景半透明,内部其他元素也半透明 2.rgba():只有背景半透明. <!DOCTYPE html> <html lang="en"> ...

  4. [Windows Server 2012] Tomcat安全加固方法

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com ★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频. ★ 本节我们将带领大家:Tomca ...

  5. Java_Web三大框架之Hibernate配置文件(二)

    下面介绍一下编写Hibernate的配置文件,使用Hibernate操作数据库. 开始部署:下载需要的jar包               下载Hibernate           Hibernat ...

  6. mysql幻读

    开启a,b两个数据库连接,a.b都开启事务后,b插入了一条数据R并提交,验证对a的操作造成的影响 select select for update update R update R 后 select ...

  7. PHP 之文件锁解决并发问题

    一.参数说明 $handle: 文件资源 $operation: 锁的类型 LOCK_SH: 共享锁 LOCK_EX: 排他锁 LOCK_UN: 释放锁 $wouldblock: 设置为true的时候 ...

  8. dotfuscator 如何设置

  9. 开发LED屏幕页面遇到的问题

    上上个礼拜公司的展销会活动需要一个展示在LED大屏幕的页面,顶部显示平台交易总金额,左右两边分别是厂家和买家实时交易记录,具体页面长下面这个样子 需求评审的时候产品说顶部的总金额要有一个数字滚动或者翻 ...

  10. SDOI2018退役记

    在NOIp2017中,我意识到自己啥也不会.如今SDOI2018快来了,自己还是啥也不会.高一两次考试注定以打两次酱油告终.还是记录一下,到NOIp之后如果还没有退役的话,那这个博客可能还会继续更新吧 ...