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大的方法

  • 相关阅读:
    MongoDB 启动和关闭
    java protostuff 序列化反序列化工具
    第一天
    第六章
    第六章
    第六章
    第六章
    第五章---面向对象---1.软件开发/2.异常处理/3.try...except的详细用法
    第五章-面向对象-1.元类介绍/2.自定义元类控制类的行为/3.控制类的实例化行为/4.控制类的实例化行为的应用
    第五章---面向对象---1.绑定方法与非绑定方法介绍/2.绑定方法与非绑定方法应用/3.反射/4.内置方法
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9283241.html
Copyright © 2011-2022 走看看