线段树好题! P2824 [HEOI2016/TJOI2016]排序 题解

这篇具有很好参考价值的文章主要介绍了线段树好题! P2824 [HEOI2016/TJOI2016]排序 题解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目传送门

前言

线段树好题!!!!
咕咕了挺久的一道题目,很早之前就想写了,今天终于找了个时间A掉了。

题意

给定一个 \(1\)\(n\) 的排列,有 \(m\) 次操作,分两种类型。
1.0 l r表示将下标在 \([l, r]\) 区间中的数升序排序。
2.1 l r表示将下标在 \([l, r]\) 区间中的数降序排序。
给定一个数 \(q\) 询问最后 \(q\) 位置上的数。

\(Solution\)

看到数据范围,发现前 \(30\) 分是可以暴力的,这里不多赘述。
注意到 \(n,m\leqslant 10^5\) ,优先考虑 \(O(nlogn)\)\(O(n \sqrt n)\) 做法。对一个序列进行操作,自然想到,线段树,但是线段树不支持区间排序那怎么办呢。
考虑对一段 \(01\) 串做排序,显然排完序后会变成 \(00011\)\(11100\) 这种形式,可以用线段树的区间推平和求和操作来完成。
但是原序列不是 \(01\) 串,我们就要把它转换成 \(01\) 串。
可以选取一个基准数,让原序列大于等于这个数的都变成 \(1\) ,其他的都是 \(0\) 就能解决这个问题了。
如果操作完之后 \(q\) 上的是 \(1\) ,说明答案至少是大于等于这个基准数的,所以二分就行了。
总复杂度 \(O(n log^2n)\)文章来源地址https://www.toymoban.com/news/detail-408711.html

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5, INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
int n, m, pos;
int a[N];
struct question
{
	int op, l, r;
} Q[N];
struct segment_tree
{
	int l, r, val, tag;
	#define l(x) tr[x].l
	#define r(x) tr[x].r
	#define val(x) tr[x].val
	#define tag(x) tr[x].tag
} tr[N << 2];
void pushup(int x)
{
	val(x) = val(x << 1) + val(x << 1 | 1);
}
void pushdown(int x)
{
	if(tag(x) == -1) return;
	val(x << 1) = (r(x << 1) - l(x << 1) + 1) * tag(x);
	tag(x << 1) = tag(x);
	val(x << 1 | 1) = (r(x << 1 | 1) - l(x << 1 | 1) + 1) * tag(x);
	tag(x << 1 | 1) = tag(x);
	tag(x) = -1;
}
void build(int l, int r, int x, int v)
{
	l(x) = l, r(x) = r, tag(x) = -1, val(x) = 0;
	if(l == r)
	{
		val(x) = (a[l] >= v);
		return;
	}
	int mid = l + r >> 1;
	build(l, mid, x << 1, v), build(mid + 1, r, x << 1 | 1, v);
	pushup(x);
}
void update(int l, int r, int x, int v)
{
	if(l <= l(x) && r(x) <= r)
	{
		tag(x) = v;
		val(x) = (r(x) - l(x) + 1) * v;
		return;
	}
	pushdown(x);
	int mid = l(x) + r(x) >> 1;
	if(l <= mid) update(l, r, x << 1, v);
	if(r > mid) update(l, r, x << 1 | 1, v);
	pushup(x);
}
int query(int l, int r, int x)
{
	if(l <= l(x) && r(x) <= r) return val(x);
	pushdown(x);
	int mid = l(x) + r(x) >> 1, res = 0;
	if(l <= mid) res += query(l, r, x << 1);
	if(r > mid) res += query(l, r, x << 1 | 1);
	return res;
}
int check(int v)
{
	build(1, n, 1, v);
	for(int i = 1;i <= m;i ++)
	{
		int l = Q[i].l, r = Q[i].r, op = Q[i].op;
		int sum = query(l, r, 1);
		if(sum == 0) continue;
		update(l, r, 1, 0);
		if(op == 0) update(r - sum + 1, r, 1, 1);
		else update(l, l + sum - 1, 1, 1);
	}
	return query(pos, pos, 1);
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n >> m;
	for(int i = 1;i <= n;i ++) cin >> a[i];
	for(int i = 1;i <= m;i ++) cin >> Q[i].op >> Q[i].l >> Q[i].r;
	cin >> pos;
	int l = 1, r = n, res;
	while(l <= r)
	{
		int mid = l + r >> 1;
		if(check(mid)) l = mid + 1, res = mid;
		else r = mid - 1;
	}
	cout << res << '\n';
    return 0;
}

到了这里,关于线段树好题! P2824 [HEOI2016/TJOI2016]排序 题解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [M链表] lc82. 删除排序链表中的重复元素 II(单链表+好题+模拟)

    链接:82. 删除排序链表中的重复元素 II 相似题目:[E链表] lc83. 删除排序链表中的重复元素(单链表+模拟) 这个题目与 83 题都很类似,一个是将重复元素全部删除,另一个是将重复元素至多保留一个。注意以下几点即可: 本题可能一个节点都不存在,且头结点也可能被删除发

    2024年01月15日
    浏览(59)
  • [BUUCTF]pwn栏目 warmup_csaw_2016 1的题解和小疑问,欢迎讨论

    首先非常感谢大家阅读我的第一篇。本文章不仅仅是题解,一些细枝末节的小问题也欢迎大家一起解答。 小问题的形式如Qx:xxxxxxx? 欢迎发现小问题并讨论~~ N1nE是本人另外一个名字,目前主要学习pwn方向,此文章以及后续别的文章,如有不当欢迎补充与纠正。 题目来自bu

    2023年04月08日
    浏览(32)
  • 【题解】合并两个排序的链表

    题目链接:合并两个排序的链表 解题思路1:迭代 创建一个新的单链表,对两个链表进行迭代,每次取较小元素放入新链表中,直至某一个链表为空,则结束循环,接着判断是否有某个链表没有遍历结束,再将未遍历结束的链表部分放入结果链表中。 一般创建单链表,都会设

    2024年02月15日
    浏览(46)
  • 湘大 XTU OJ 1097 排序 题解:c++ 函数库的使用 快速排序 归并排序 冒泡排序

    1097 排序 Description N个整数,将其排序输出。 输入 第一行是一个整数K(1=K=20),表示有多少个样例, 每个样例的第一行是一个整数N(1=N=1,000) 和一个字符X,X为A时表示升序排序,为D时为降序排列;第二行为N个整数,每个整数都可以使用int表示, 每个之间用一个空格隔开。

    2024年02月13日
    浏览(42)
  • PTA数组及排序查找题解与解题思路

    函数题目为平台提供的裁判程序调用所完成的函数进行判题,题目规定语言为C语言 本题较为简单,考察的是如何遍历一个二维数组,只需要两个循环依次遍历其每个维度和元素即可 如何寻找最大值? 只需要在遍历每个元素的过程中,使用一个变量记录最大值,当出现更大的

    2024年02月08日
    浏览(53)
  • P8719 [蓝桥杯 2020 省 AB2] 字串排序题解

    根据题目意思,我们构造的字符串需要满足冒泡排序交换次数为 V V V 次,越短越好的情况下输出字典序最小的那一个。于是我们先从字符串的长度开始考虑。 如何求字符串的最短长度是多少 设字符串长度为 l e n len l e n , 若该长度的字符串能构造出的最大交换数 ≥ V geq V ≥

    2024年02月08日
    浏览(63)
  • 【leetcode题解C++】34.在排序数值中查找第一个和最后一个位置

    给你一个按照非递减顺序排列的整数数组  nums ,和一个目标值  target 。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值  target ,返回  [-1, -1] 。 你必须设计并实现时间复杂度为  O(log n)  的算法解决此问题。 示例 1: 示例 2: 示例 3: 思路

    2024年01月16日
    浏览(40)
  • Leetcode刷题笔记题解(C++):83. 删除排序链表中的重复元素

    思路:链表相关的问题建议就是画图去解决,虽然理解起来很容易,但就是写代码写不出来有时候,依次去遍历第二节点如果与前一个节点相等则跳过,不相等则遍历第三个节点

    2024年02月22日
    浏览(68)
  • 湘大 XTU OJ 1291 Buying Gifts 题解(非常详细):枚举 维护最小值 排序

    1291 Buying Gifts 快到年末了,Boss Liu准备在年会上发些礼物, 由于不想礼物的价格区别太大 ,Boss Liu希望 最好的礼物与最差的礼物价格相差越小越好 。 当然, 如果存在相同的选择,Boss Liu希望花的钱越少越好 。 Boss Liu把这个买礼物的任务给你,你决定写个程序来帮助自己计算

    2024年02月13日
    浏览(46)
  • 《图》经典题题解(拓扑排序,DFS,BFS,Floyd,Dijkstra,LCA最近公共祖先,最小生成树,最短路径)(ACM)

    目录 拓扑排序 / 家谱树 p1359租用潜艇 P1938[USACO09NOV] Job Hunt S  最短路计数 797. 所有可能的路径  200.岛屿数量 DFS BFS 695.岛屿的最大面积 DFS BFS P1119 灾后重建  P1629 邮递员送信 法一:Floyd 法二:Dijkstra P3379 【模板】最近公共祖先(LCA) 最小生成树 法一:prim算法 法二:Kruskal算

    2024年04月14日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包