首页 > 其他分享 >一些排序相关典题

一些排序相关典题

时间:2023-04-19 12:24:18浏览次数:35  
标签:二分 include log int mid long 典题 相关 排序

HDU6231 & P2824

HDU6231 K-th Number

给你一个长度为 \(n\) 的序列 \(A\),有一个初始为空的序列 \(B\),把 \(A\) 中所有子区间的第 \(K\) 大加入序列 \(B\) 中,求 \(B\) 中的第 \(M\) 大

\(n\le 10^5,K\le n\)

考虑二分答案,假设当前答案是 \(x\),把原序列中所有 \(<x\) 的元素变成 \(0\),所有 \(\ge x\) 的元素变成 \(1\)

只有包含 \(1\) 的个数 \(\le K\) 的区间,加入的数才会排在 \(x\) 的前面,算出 \(x\) 的前面有多少个数,来二分第 \(M\) 个位置即可

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int sum[N];
int n, k;
long long m;

inline bool check(int x){
    long long res = 0;
    for(int i = 1; i <= n; i++){
        sum[i] = sum[i-1];
        if(a[i] >= x){
            sum[i] ++;
        }
    }

    for(int i = 1, j = 1; i <= n && j <= n; i ++){
        while(sum[j] - sum[i-1] < k && j <= n)    j++;
        res += n - j + 1;
    }
    return res >= m;
}

int main(){
    int T;
    scanf("%d", &T);

    while(T--){
        scanf("%d%d%lld", &n, &k, &m);
        for(int i = 1; i <= n; i ++){
            scanf("%d", &a[i]);
            b[i] = a[i];
        }
        sort(b + 1, b + n + 1);

        int l = 1, r = n+1, ans;
        while(l < r){
            int mid = (l + r) >> 1;
            if(check(b[mid]))  { ans = mid, l = mid + 1;}
            else    r = mid;
        }

        printf("%d\n", b[ans]);
    }
    return 0;
}

P2824 [HEOI2016/TJOI2016]排序

同样的套路,考虑二分答案

假设当前二分的值是 \(x\),把序列中所有 \(<x\) 的都变成 \(0\),所有 \(\ge x\) 的都变成 \(1\)

则排序的操作就是区间清空,前/后缀赋 \(1\)

按第 \(q\) 个位置的数是否为 \(1\) 二分即可(是否 \(\ge x\))

二分复杂度是 \(O(\log n)\) 的,每次建线段树,暴力执行询问是 \(O(n\log n+m\log n)\)

复杂度是 \(O((n+m)\log^2 n)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector>

using namespace std;
const int N = 1e5 + 10;
int n, m;
int a[N], b[N];
int base[N];
int Q;

struct Operator {
	int l, r;
	int type;
}q[N];

struct Node {
	int l, r;
	int sum;
	int tag;
}tr[N << 4];

inline void pushup(int u) {
	tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void pushdown(int u) {
	if(tr[u].tag == -1)
		return ;
	Node &ls = tr[u << 1], &rs = tr[u << 1 | 1];
	ls.sum = tr[u].tag * (ls.r - ls.l + 1);
	rs.sum = tr[u].tag * (rs.r - rs.l + 1);
	ls.tag = tr[u].tag;
	rs.tag = tr[u].tag;
	tr[u].tag = -1;
}

void build(int u, int l, int r) {
	tr[u].l = l, tr[u].r = r;
	tr[u].tag = -1;
	if(l == r) {
		tr[u].sum = base[l];
		return ;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	pushup(u);
}

int query_seg(int u, int l, int r) {
	if(l <= tr[u].l && tr[u].r <= r) {
		return tr[u].sum;
	}
	int ans = 0;
	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	if(l <= mid)
		ans += query_seg(u << 1, l, r);
	if(r > mid)
		ans += query_seg(u << 1 | 1, l, r);
	return ans;
}

int query(int u, int x) {
	if(tr[u].l == tr[u].r) {
		return tr[u].sum;
	}
	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	if(x <= mid)
		return query(u << 1, x);
	else
		return query(u << 1 | 1, x);
}

void modify(int u, int l, int r, int k) {
	if(l <= tr[u].l && tr[u].r <= r) {
		tr[u].sum = k * (tr[u].r - tr[u].l + 1);
		tr[u].tag = k;
		return ;
	}
	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	if(l <= mid)
		modify(u << 1, l, r, k);
	if(r > mid)
		modify(u << 1 | 1, l, r, k);
	pushup(u);
}

void DoOperator(int x) {
	int Num1 = query_seg(1, q[x].l, q[x].r);
	modify(1, q[x].l, q[x].r, 0);
	if(q[x].type == 0)
		modify(1, q[x].r - Num1 + 1, q[x].r, 1);
	else
		modify(1, q[x].l, q[x].l + Num1 - 1, 1);
}

bool check(int x) {
	for(int i = 1; i <= n; i++)
		base[i] = a[i] >= x;
	build(1, 1, n);
	for(int i = 1; i <= m; i++)
		DoOperator(i);	
	return query(1, Q);
}

int BinarySearch() {
	int l = 1, r = n;
	while(l < r) {
		int mid = l + r >> 1;
		if(check(b[mid]))	l = mid + 1;
		else r = mid;
	}
	return l - 1;
}

int main() {
	//freopen("sort.in", "r", stdin);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	memcpy(b, a, (n + 1) * sizeof(int));
	sort(b + 1, b + 1 + n);
	for(int i = 1; i <= m; i++)
		scanf("%d%d%d", &q[i].type, &q[i].l, &q[i].r);
	scanf("%d", &Q);	
	printf("%d\n", b[BinarySearch()]);
	return 0;
}

标签:二分,include,log,int,mid,long,典题,相关,排序
From: https://www.cnblogs.com/lostintianyi/p/17332904.html

相关文章

  • 云计算行业的相关技术知识,主要有哪些?
    云计算是一种新型的业务交付模式,同时也是新型的IT基础设施管理方法。通过新型的业务交付模式,用户将通过网络充分利用优化的硬件、软件和网络资源,并以此为基础提供创新的业务服务。新型的IT基础设施管理方法让IT部门可以把海量资源作为一个统一的大资源进行管理,支持IT部门在大......
  • List<Integer>排序
    List<Integer>list=newArrayList<Integer>();从小到大方法:Collections.sort(list);从大到小方法:Collections.sort(list,Collections.reverseOrder());  Java8将List<Integer>转换成以逗号分割的String字符串publicstaticvoidmain(String[]args){List<Int......
  • 字典序相关贪心
    AGC010E【题意】给定一张\(n\)个节点的无向图,点有点权,小A要给每条边定向,使得无向图依然是DAG,然后小B取出一个拓扑序。小A的目标是最大化拓扑序,小B的目标是让拓扑序的点权字典序最小。\(n\le2000,m\len(n-1)/2\)【分析】这题你要是直接从拓扑序来考虑,想到某一......
  • 冒泡排序
    冒泡排序的个人理解:<!--冒泡排序--><script>vararr=[9,8,7,6,5,4,3,2,1]//定义一个数组for(letj=0;j<arr.length-1/*倒数第二论比较剩下最小值后,不必再进行下一次比较*/;j++){for(leti=0;i<arr.length......
  • 选择排序
    选择排序的个人理解:先假定数组中的第0个就是最小的数字的索引然后遍历数组,只要有一个数字比我小,那么就替换之前记录的索引直到数组遍历结束后,就能找到最小的那个索引,然后让最小的索引换到第0个的位置再来第二趟遍历,假定第1个是最小的数字的索引在遍历一次数......
  • 手撕排序算法之选择排序
    前言选择排序算法有两种,一种是直接选择排序,另一种是堆排序。他们的算法思想都离不开选择二字,其中堆排序比选择排序的更加快捷。一、直接选择排序1.排序思想以升序为例遍历数组,找到数组中最小的元素放到最前面,在从剩下的数组元素中找到最小的,依次放入,当只剩下一个元素时,已经排好。2.......
  • 排序算法-基数排序
    基数排序RadixSort1.RadixSort介绍RadixSort属于“分配式排序”(DistributionSort),又称“桶子法”(BucketSort),其是通过比较待排序序列的所有元素的各个位的值,将元素分配至“桶”中,以达到排序的目的。RadixSort是一种效率较高且稳定的排序算法,其是桶排序的扩展。RadixSor......
  • echarts相关问题
    解决echarts下钻地图,在平移和缩放后,下钻到下一级时生成的地图不在容器中间,会跑到容器外面去。 myChart.setOption(option,true)问题:echart地图三级下钻地图在平移和缩放后,点击到省,由于中心点的偏移,省跑到容器以外的地方去了,导致新生成的地图看不见。解决方法:后来发现,是重新绘制......
  • 初次排序算法学习
    直接选择排序:思路:从数组中挑出最小(最大)的数,与数组第一位(最后一位)交换位置,然后依次进行,直到最后两个元素比较完毕为止。实现:声明一个中间变量max,用于存放最大值;声明一个变量m,用于存放最大值对应的序号。外侧循环次数是n-1,n是数组元素个数,意思是挑出n-1个最大值,剩下的自然是最......
  • js 选择器操作相关
    Javascript知识【jQuery选择器】 https://blog.csdn.net/m0_64550837/article/details/126231445 CSS选择器https://blog.csdn.net/weixin_44214326/article/details/128093869 ......