zoukankan      html  css  js  c++  java
  • 主席树-可持久化线段树学习笔记

    可持久化版本的线段树

    支持对历史版本的一些操作

    每个版本对应一个根

    这样也就相当于每个版本有一棵线段树

    有信息被更改的节点就新建一个

    没有则与原来的共用

    线段树用来维护出现次数,所以一般都用到离散化

    有了每个数字出现次数自然就可以查第 k 大了

    那么区间第 k 大呢?

    其实主席树大概是一个前缀和套线段树的数据结构

    这样利用前缀和算出区间内出现次数

    也就可以得出区间第 k 大了

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    
    const int MAXN = 200001;
    
    struct Node{
    	int ls, rs, sum;
    	Node(){ls = rs = sum = 0;}
    }t[MAXN << 5];
    int n, m, sizb, poolcur;
    int a[MAXN], b[MAXN], rnk[MAXN], Root[MAXN << 5];
    
    inline int rd() {
    	register int x = 0;
    	register char c = getchar();
    	register bool f = false;
    	while(!isdigit(c)) {
    		if(c == '-') f = true;
    		c = getchar();
    	}
    	while(isdigit(c)) {
    		x = x * 10 + c - 48;
    		c = getchar();
    	}
    	return f ? -x : x;
    }
    int build(int l, int r) {
    	int cur = ++poolcur;
    	if(l == r) return cur;
    	int mid = ((l + r) >> 1);
    	t[cur].ls = build(l, mid);
    	t[cur].rs = build(mid + 1, r);
    	return cur;
    }
    int Insert(int l, int r, int cur, int dst) {
    	int newcur = ++poolcur;
    	t[newcur] = t[cur];
    	++t[newcur].sum;
    	if(l == r) return newcur;
    	int mid = ((l + r) >> 1);
    	if(dst <= mid) t[newcur].ls = Insert(l, mid, t[cur].ls, dst);
    	else t[newcur].rs = Insert(mid + 1, r, t[cur].rs, dst);
    	return newcur;
    }
    int query(int x, int y, int l, int r, int k) {
    	if(l == r) return l;
    	int lsiz = t[t[y].ls].sum - t[t[x].ls].sum;
    	int mid = ((l + r) >> 1);
    	if(k <= lsiz) return query(t[x].ls, t[y].ls, l, mid, k);
    	else return query(t[x].rs, t[y].rs, mid + 1, r, k - lsiz);
    }
    inline void init() {
    	sort(b + 1, b + n + 1);
    	sizb = unique(b + 1, b + n + 1) - b - 1;
    	for(int i = 1; i <= n; ++i) rnk[i] = lower_bound(b + 1, b + sizb + 1, a[i]) - b;
    	return;
    }
    
    int main() {
    	n = rd(); m = rd();
    	for(int i = 1; i <= n; ++i) a[i] = b[i] = rd();
    	init();
    	Root[0] = build(1, sizb);
    	for(int i = 1; i <= n; ++i) Root[i] = Insert(1, sizb, Root[i - 1], rnk[i]);
    	int l, r, k;
    	while(m--) {
    		l = rd(); r = rd(); k = rd();
    		printf("%d
    ", b[query(Root[l - 1], Root[r], 1, sizb, k)]);
    	}
    	return 0;
    }
    

      

    禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载 ,用户转载请注明出处:https://www.cnblogs.com/xcysblog/
  • 相关阅读:
    PAT(B) 1037 在霍格沃茨找零钱(Java)
    PAT(B) 1043 输出PATest(Java)统计
    PAT(B) 1063 计算谱半径(Java)
    绘制虚线
    contentMode
    数字签名是什么
    动态设置 button的 name 的话 闪动的问题 解决
    setValuesForKeysWithDictionary 的用法
    获得 当前时间
    iOS 键盘类型
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9069824.html
Copyright © 2011-2022 走看看