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

    今天第一次接触可持久化数据结构,还是有必要总结一下的。

    首先对于查找第k大的问题,先搞清楚怎么样通过利用N颗线段树来求解。如果是求全局第K大,那么可以把数字的值作为位置插入线段树,然后通过区间和+二分来找到第k个位置。因为是通过区间和来找第k大的,显然是满足前缀和性质的,所以查询l,r区间的第k打,就直接根据1-l - 1,1-r两个区间建立两颗线段树,然后通过节点依次相减来求得第k大值。所以这样子解需要的内存空间是n*n*logn的(不需要管数的范围,范围再大也可以通过离散化缩小到n)。

    但是注意到每一棵树相对于前一颗只有一个节点被修改了,最多只有logn个节点变化,所以只存储修改过的节点,然后用指针指向原来的的不变的节点就好。

    第一次写,实现起来感觉还是有点蛋疼的。不过也不长=。=

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    const int maxn = 100000 + 10;
    const int maxm = maxn * 30;
    
    int lc[maxm], rc[maxm], sumv[maxm], cnt;
    int root[maxn], n, q, a[maxn];
    vector<int> vnum;
    
    void init() {
    	cnt = 1;
    	root[0] = 0;
    }
    
    void build(int rt, int l, int r) {
    	sumv[rt] = 0;
    	if (l == r) return;
    	int mid = (l + r) >> 1;
    	lc[rt] = cnt++; rc[rt] = cnt++;
    	build(lc[rt], l, mid);
    	build(rc[rt], mid + 1, r);
    }
    
    
    void update1(int rt, int prt, int l, int r, int pos, int val) {
    	int mid = (l + r) >> 1;
    	if (l == r) return;
    	if (pos <= mid) {
    		int newrt = cnt++;
    		lc[rt] = newrt;
    		sumv[newrt] = sumv[lc[prt]] + val;
    		rc[rt] = rc[prt];
    		update1(newrt, lc[prt], l, mid, pos, val);
    	}
    	else {
    		int newrt = cnt++;
    		rc[rt] = newrt;
    		sumv[newrt] = sumv[rc[prt]] + val;
    		lc[rt] = lc[prt];
    		update1(newrt, rc[prt], mid + 1, r, pos, val);
    	}
    }
    
    void update(int rt, int pos, int val) {
    	root[rt] = cnt++;
    	sumv[root[rt]] = sumv[root[rt - 1]] + val;
    	update1(root[rt], root[rt - 1], 1, n, pos, val);
    }
    
    int query(int lroot, int rroot, int l, int r, int k) {
    	int mid = (l + r) >> 1, nowsum = sumv[lc[rroot]] - sumv[lc[lroot]];
    	if (l == r) return vnum[l - 1];
    	if (nowsum >= k) return query(lc[lroot], lc[rroot], l, mid, k);
    	else return query(rc[lroot], rc[rroot], mid + 1, r, k - nowsum);
    }
    
    int getid(int val) {
    	return lower_bound(vnum.begin(), vnum.end(), val) - vnum.begin() + 1;
    }
    
    int main() {
    	while (scanf("%d%d", &n, &q) != EOF) {
    		init(); vnum.clear();
    		build(root[0], 1, n);
    		for (int i = 1; i <= n; i++) {
    			scanf("%d", &a[i]);
    			vnum.push_back(a[i]);
    		}
    		sort(vnum.begin(), vnum.end());
    		vnum.erase(unique(vnum.begin(), vnum.end()), vnum.end());
    		for (int i = 1; i <= n; i++) {
    			update(i, getid(a[i]), 1);
    		}
    		while (q--) {
    			int l, r, k; scanf("%d%d%d", &l, &r, &k);
    			int ret = query(root[l - 1], root[r], 1, n, k);
    			printf("%d
    ", ret);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    NYOJ 32(组合数)
    NYOJ 289(01背包)
    批量修改文件(图片)名称
    解决IIS7虚拟目录出现HTTP 错误 500.19(由于权限不足而无法读取配置文件)的问题
    MPP(最下正周期)
    wcf学习网站
    winform中用户输入查询与拼音首字母的结合,提高用户的操作体验 (转)
    通过SvcUtil.exe生成客户端代码和配置(转)
    WinMail 搭建邮件服务器。
    quick easy ftp server软件在机子上架设了个服务器
  • 原文地址:https://www.cnblogs.com/rolight/p/4082248.html
Copyright © 2011-2022 走看看