题目大意

  给出一个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. android Activity实现底部滑动弹出窗口及源码下载地址

    在做微信.微博.qq等分享时,一般是点击分享按钮后会从底部弹出滑动窗口,然后选择要分享的社交平台进行分享.今日头条.腾讯新闻等内容App的评论也是从底部滑动弹出输入窗口,进行评论输入的.本篇文章就讲讲 ...

  2. pengyue-form 模块 dropdown 关系联动

    <script> window.onload=function() { var school= document.getElementById("dnn_ctr5973_View ...

  3. WebAPI PUT,DELETE请求404

  4. yum进程被占用

    使用yum安装软件的时候出现,/var/run/yum.pid 已被锁定,PID 为 6503 的另一个程序正在运行的问题 [root@localhost mysql]# yum install gc ...

  5. centos添加永久的环境变量

    cd /etc/profile.d/ 创建一个sh文件 vi dotnetpath.sh 内容如下: export PATH=$PATH:/opt/dotnet 保存,重启,这就有了一个永久的环境变量

  6. 视频cover占满

    /* 关键属性 */ object-fit: fill; //被替换的内容的大小,以填补该元素的内容框:对象的具体对象的大小是元素的使用宽度和高度. object-fit: contain;被替换的内 ...

  7. Python---HTML表单

    一. http:80 https:443 -------------------------- 二.

  8. vue-router的基本使用和配置

    1.在main.js文件中引入相关模块以及组件及实例化vue对象配置选项路由及渲染App组件 默认设置如下: import Vue from 'vue' import App from './App' ...

  9. Luogu P1256 显示图像

    P1256 显示图像 题目描述 古老的显示屏是由N×M个像素(Pixel)点组成的.一个像素点的位置是根据所在行数和列数决定的.例如P(2,1)表示第2行第1列的像素点.那时候,屏幕只能显示黑与白两种 ...

  10. (40). springboot + devtools(热部署)【从零开始学Spring Boot】

    我们之前在在()Spring Boot热部署[从零开始学Spring Boot] (http://412887952-qq-com.iteye.com/blog/2291518 )讲过通过使用spri ...