题目大意

  给出一个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. python gdal 数组生成图片

    cols = array.shape[1]rows = array.shape[0]originX = rasterOrigin[0]originY = rasterOrigin[1]driver = ...

  2. Java Web框架前景浅析

    基于三(多)层架构模式,典型WEB系统的总体架构如下图所示: 在上述分层架构中,整个应用被划分为两大部分: 客户端:基于浏览器提供信息展现.用户交互等功能.所采用的技术主要有:HTML/HTML5.J ...

  3. 删除ListView item数据 页面不刷新

    最近碰到一个匪夷所思的事情.就是我删除listView中一条item数据  网络请求成功了 但是页面不成功,一番折腾 ,找到问题 ,原来我给item 添加了北京点击事假,又给listView 被禁设置 ...

  4. sql 分析 依赖beanutils

    你还在为sql语句的拼接而烦恼吗? sql语句支持表达式了! package com.newland.bi.webservice.common.manage; import java.util.Arr ...

  5. GitHub代码托管平台搭建

    GitHub代码托管平台搭建 注册账户以及创建仓库 要想使用github第一步当然是注册github账号了, github官网地址:https://github.com/. 之后就可以创建仓库了(免费 ...

  6. cookie范例

    GET /locate/api/getLocByIp?key=C6E22B7D480E3312C74EC7EF013E50C5&callback=bowlder.cb._0 HTTP/1.1 ...

  7. 通过PHP怎样取到android系统下apk应用的包名,版本号等信息

    公司项目关系,要求在通过PHP解析android系统应用apk包内的一切可用的信息.比如说:APK包名,版本号,版本名,安装权限等一系列关于对应包的信息.通过google查找相关的解决方案,都没有找到 ...

  8. Django中 基于form的注册,基于ajax的登录

    1 form.py中写register的的form组件 from django import forms class Register(forms.Form): # 注册的form username ...

  9. 安装 jdk 和 IDE软件

    1.jdk的安装 通过官方网站获取JDK http://www.oracle.com 针对不同操作系统,下载不同的JDK版本 识别计算机的操作系统 下载完后进行安装,傻瓜式安装,下一步下一步即可.用j ...

  10. C/C++ 中野指针产生的问题

    野指针产生的问题: 野指针的定义: > 野指针是指:指向一个已删除的对象或未申请访问受限内存区域的指针.与空指针不同,野指针无法通过简单地判断是否为NULL避免,而只能通过养成良好的编程习惯来尽 ...