zoukankan      html  css  js  c++  java
  • POJ 2104 K-th Number 主席树

    题意:

    给出(n(1 leq n leq 10^5))个数字和(m(1 leq m leq 5000))个询问。
    每次询问形式如下:

    • (l \, r \, k)表示询问区间([l,r])从小到大排序后第(k)个数字的大小。

    分析:

    推荐这篇主席树的教程,里面的图片十分简洁明了,一图胜千言。
    主席树的本质就是可持久化线段树,为了节省空间,相邻两棵树共用了相同的的区间节点(也就是数据不发生变换的区间)。
    仅对于数据发生变化的区间新建节点来更新维护信息。

    区间维护的信息是值域上数字出现的次数,所以我们先把输入数据离散化一下。
    查询第(k)小的时候类似于(BST)中的名次树,先查询区间([l,r])中数字的个数(cnt)(m=frac{l+r}{2})是区间的中点。

    • 如果(cnt geq k),那么第(k)小的值一定在左区间([l, m])中,递归求解左区间的第(k)
    • 否则,第(k)小的值一定在右区间([m, r])中,递归求解右区间的第(k-cnt)
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 100000 + 10;
    
    struct Node
    {
    	int lch, rch, sum;
    };
    
    int sz;
    Node T[maxn << 5];
    
    int newnode() {
    	T[sz].lch = T[sz].rch = T[sz].sum = 0;
    	return sz++;
    }
    
    int build(int L, int R) {
    	int rt = newnode();
    	if(L == R) return rt;
    	int M = (L + R ) / 2;
    	T[rt].lch = build(L, M);
    	T[rt].rch = build(M + 1, R);
    	return rt;
    }
    
    int update(int pre, int L, int R, int p) {
    	int rt = newnode();
    	T[rt].lch = T[pre].lch;
    	T[rt].rch = T[pre].rch;
    	T[rt].sum = T[pre].sum + 1;
    	if(L == R) return rt;
    	int M = (L + R) / 2;
    	if(p <= M) T[rt].lch = update(T[pre].lch, L, M, p);
    	else T[rt].rch = update(T[pre].rch, M + 1, R, p);
    	return rt;
    }
    
    int query(int s, int t, int L, int R, int k) {
    	if(L == R) return L;
    	int M = (L + R) / 2;
    	int cnt = T[T[t].lch].sum - T[T[s].lch].sum;
    	if(cnt >= k) return query(T[s].lch, T[t].lch, L, M, k);
    	else return query(T[s].rch, T[t].rch, M+1, R, k - cnt);
    }
    
    int n, m;
    int a[maxn], b[maxn], tot, root[maxn];
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= n; i++) {
    		scanf("%d", a + i);
    		b[i] = a[i];
    	}
    	sort(b + 1, b + 1 + n);
    	tot = unique(b + 1, b + 1 + n) - (b + 1);
    
    	sz = 0;
    	root[0] = build(1, tot);
    	for(int i = 1; i <= n; i++) {
    		int id = lower_bound(b + 1, b + 1 + tot, a[i]) - b;
    		root[i] = update(root[i - 1], 1, tot, id);
    	}
    
    	while(m--) {
    		int l, r, k; scanf("%d%d%d", &l, &r, &k);
    		int ans = query(root[l - 1], root[r], 1, tot, k);
    		printf("%d
    ", b[ans]);
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    【Java Web开发学习】Spring加载外部properties配置文件
    【Java Web开发学习】Spring4整合thymeleaf视图解析
    快速入门系列--MVC--06视图
    快速入门系列--WebAPI--03框架你值得拥有
    快速入门系列
    iOS 自己封装的网络请求,json解析的类
    iOS 本地通知
    iOS8 自定义navigationItem.titleView
    iOS8 UICollectionView横向滑动demo
    基于Spring开发
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/5279729.html
Copyright © 2011-2022 走看看