zoukankan      html  css  js  c++  java
  • 序列内第k小查询(线段树)

    最近请教了一下大佬怎么求序列内第k大查询,自己又捣鼓了一下,虽然还没有懂得区间第k大查询,不过姑且做一个记录先吧

    因为每个元素大小可能很大而元素之间不连续,所以我们先离散化处理一下,程序中的ori[ ]代表原序列,离散化后每个key对应一个值,mem[ ]存的是key对应的值:mem[i]代表离散化后 i 代表的值,a[i]代表离散化后有几个i对应的值(mem[i]的个数)

    离散化之后建树,sum中存的是有序的元素总个数具体可以看程序,那么如何查询?我们查询线段树的sum,若tree[lid].sum >= k ,说明第k大一定在左儿子区间,因为线段树是以有序数列来构建的,每个叶子排起来是有序的(抠一下手指就出来了),说明k在左边。同理 若 tree[lid].sum < k 说明左边全部在一起都没有 k 个,答案自然就在右边了

    因为从右边区间出发,已经排除全部左边节点了,所以k要减去左边的sum

    这样一直找到叶子节点,找到的叶子对应的就是离散化后的key了,我们在利用mem输出就好

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int RD(){
        int out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    #define lid (id << 1)
    #define rid (id << 1) | 1
    const int maxn = 100019;
    int num,na;
    int ori[maxn];
    int mem[maxn];
    struct sag_tree{
    	int l,r,sum;
    	}tree[maxn << 2];
    int a[maxn];
    void build(int id,int l,int r){
    	tree[id].l = l;
    	tree[id].r = r;
    	if(l == r){
    		tree[id].sum = a[l];
    		return ;
    		}
    	int mid = (l + r) >> 1;
    	build(lid,l,mid);
    	build(rid,mid + 1,r);
    	tree[id].sum = tree[lid].sum + tree[rid].sum;
    	}
    	
    int query(int id,int k){
    	if(tree[id].l == tree[id].r)return tree[id].l;
    	if(tree[lid].sum < k)return query(rid,k - tree[lid].sum);
    	else if(tree[lid].sum >= k)return query(lid,k);
    	}
    	
    int main(){
    	num = RD();na = RD();
    	for(int i = 1;i <= num;i++){
    		ori[i] = RD();
    		}
    	sort(ori + 1,ori + 1 + num);
    	int n = 0;
    	for(int i = 1;i <= num;i++){
    		if(i == 1 || ori[i] != ori[i - 1]){
    			n++;
    			}
    		a[n]++;
    		mem[n] = ori[i];
    		}
    	build(1,1,n);
    	int k;
    	for(int i = 1;i <= na;i++){
    		k = RD();
    		cout<<mem[query(1,k)]<<endl;
    		}
    	return 0;
    	}
    

    推一下可以得到,序列第k大就是序列第(num - k + 1)小,所以很好解决


    upd 18.7.9

    后面发现,其实这也是treap查找序列第k大的方法

  • 相关阅读:
    伪造mysql服务端实现任意读取
    客户端session安全问题(flask)
    systemd教程
    MySQL的一些常用基本命令的使用说明
    AMD、CMD、CommonJs和ES6的区别
    for in与for of的区别,以及forEach,map,some,every,filter的区别
    EcmaScript 6 十大常用特性
    单行省略号与多行省略号
    Array.prototype.slice.call()详解及转换数组的方法
    返回顶部
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9283241.html
Copyright © 2011-2022 走看看