zoukankan      html  css  js  c++  java
  • 洛谷P3834 【模板】可持久化线段树 2(主席树)

    题目背景

    这是个非常经典的主席树入门题——静态区间第 kk 小。

    数据已经过加强,请使用主席树。同时请注意常数优化

    题目描述

    如题,给定 nn 个整数构成的序列 aa,将对于指定的闭区间 [l,r][l,r] 查询其区间内的第 kk 小值。

    输入格式

    第一行包含两个整数,分别表示序列的长度 nn 和查询的个数 mm
    第二行包含 nn 个整数,第 ii 个整数表示序列的第 ii 个元素 aia**i​。
    接下来 mm 行每行包含三个整数 l,r,kl,r,k , 表示查询区间 [l,r][l,r] 内的第 kk 小值。

    输出格式

    对于每次询问,输出一行一个整数表示答案。

    输入输出样例

    输入 #1复制

    5 5
    25957 6405 15770 26287 26465 
    2 2 1
    3 4 1
    4 5 1
    1 2 2
    4 4 1
    

    输出 #1复制

    6405
    15770
    26287
    25957
    26287
    

    说明/提示

    样例 1 解释

    n=5n=5,数列长度为 55,数列从第一项开始依次为{25957,6405,15770,26287,26465}{25957,6405,15770,26287,26465}。

    • 第一次查询为 [2,2][2,2] 区间内的第一小值,即为 64056405。
    • 第二次查询为 [3,4][3,4] 区间内的第一小值,即为 1577015770。
    • 第三次查询为 [4,5][4,5] 区间内的第一小值,即为 2628726287。
    • 第四次查询为 [1,2][1,2] 区间内的第二小值,即为 2595725957。
    • 第五次查询为 [4,4][4,4] 区间内的第一小值,即为 2628726287。

    数据规模与约定

    • 对于 20%20% 的数据,满足 1≤n,m≤101≤n,m≤10。
    • 对于 50%50% 的数据,满足 1≤n,m≤1031≤n,m≤103。
    • 对于 80%80% 的数据,满足 1≤n,m≤1051≤n,m≤105。
    • 对于 100%100% 的数据,满足 1≤n,m≤2×1051≤n,m≤2×105,∣ai∣≤109∣a**i∣≤109,1≤l≤r≤n1≤lrn,1≤k≤r−l+11≤krl+1。

    板题,因为求的是区间第k小,于是离散化后建主席树查询即可。

    #include <bits/stdc++.h>
    #define N 200005
    using namespace std;
    int n, q;
    int cnt = 0;//总的节点数
    int sum[N << 5], L[N << 5], R[N << 5];//主席树一定不能吝啬空间
    int a[N], b[N];
    int T[N];
    int build(int l, int r) {
    	int rt = ++cnt;
    	sum[rt] = 0;
    	int mid = (l + r) >> 1;
    	if(l < r) {
    		L[rt] = build(l, mid);
    		R[rt] = build(mid + 1, r);
    	}
    	return rt;
    }
    int modify(int pre, int l, int r, int x) {
    	int rt = ++cnt;
    	L[rt] = L[pre]; R[rt] = R[pre];
    	sum[rt] = sum[pre] + 1;
    	if(l < r) {
    		int mid = (l + r) >> 1;
    		if(x <= mid) L[rt] = modify(L[pre], l, mid, x);
    		//注意这里是x <= mid !!!而不是线段树常见写法
    		//因为这是对权值建立的线段树!
    		else R[rt] = modify(R[pre], mid + 1, r, x);
    	}
    	return rt;
    }
    int query(int u, int v, int l, int r, int k) {
    	if (l >= r) return l;
        int x = sum[L[v]] - sum[L[u]];
        int mid = (l + r) >> 1;
        if (x >= k) return query(L[u], L[v], l, mid, k);
        else return query(R[u], R[v], mid+1, r, k-x);
    }
    int main() {
    	cin >> n >> q;
    	vector<int> v;
    	for(int i = 1; i <= n; i++) {
    		cin >> a[i];
    		v.push_back(a[i]);
    	}
    	sort(v.begin(), v.end());
    	vector<int>::iterator it = unique(v.begin(), v.end());
    	v.erase(it, v.end());
    	T[0] = build(1, v.size());
    	for(int i = 1; i <= n; i++) {
    		int tmp = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
    		b[tmp] = a[i];
    		T[i] = modify(T[i - 1], 1, v.size(), tmp);
    	}
    	for(int i = 0; i < q; i++) {
    		int l, r, k;
    		cin >> l >> r >> k;
    		int ans = query(T[l - 1], T[r], 1, v.size(), k);
    		cout << b[ans] << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    数据预处理
    数据挖掘-聚类分析
    数据挖掘分类--判别式模型 ----支持向量机
    神经网络
    数据挖掘-贝叶斯定理
    数据挖掘之分类和预测
    关于stm32的IO口的封装
    星际炸弹——炸弹爆炸时间计算
    共阳极数码管三极管驱动
    自定义的TIME.H头文件
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/15171047.html
Copyright © 2011-2022 走看看