zoukankan      html  css  js  c++  java
  • 主席树模板

    引入

    首先请求出:

    ​ 长度为n的序列

    ​ m次询问全局第k小

    做法:

    ​ 画一棵(权值)线段树+前缀和+手动模拟,请记住此过程

    之后,请思考;

    ​ 长度为n的序列

    ​ m次询问区间[l, r]中第k小值

    ​ 值域 ±1e9

    ​ n≤2e5 , m≤2e5

    做法: 可持久化线段树(即 线段树+前缀和+差分)

    原理

    每个点以其前缀和,构建权值线段树, 用 [1, r]建得的线段树 - [1, l-1]建得的线段树 (即把这两颗形状一样的线段树上的每个节点的权值相减), 得到的即为区间[l, r]建得的线段树, 这样之后,我们就可以求出(这棵线段树的)全局第k小值,而这个值也就是区间[l, r]的第k小值

    代码实现

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MAX 200000+99
    
    int n, m;
    
    struct da
    {
    	int n,a,k;//输入顺序n,原数据a,离散化之后数据k 
    }a[MAX];
    int ys[MAX];//da数组和原数的映射关系 
    
    bool cmp1(da x, da xxx) {
    	return x.a < xxx.a ;//用于离散化 
    }
    bool cmp2(da x, da xxx) {
    	return x.n < xxx.n ;
    }
    
    int root[MAX];//保存森林中的各个根节点 //时间戳? 
    int nodecnt;//所有节点的数量 
    struct tree{
    	int sum;
    	int lson, rson;
    }tr[MAX<<5];//2n+nlogn
    
    int build(int l, int r) {//建空树 
    	int now = ++nodecnt;//加点 
    	if(l == r) return now;
    	int mid = (l+r)>>1;
    	tr[now].lson = build(l, mid);
    	tr[now].rson = build(mid+1, r);
    	return now;
    }
    
    int insert(int last, int l, int r, int x) {//建权值线段树 
    	int now = ++nodecnt;
    	tr[now].sum = tr[last].sum + 1;
            if(l == r) return now;
    	tr[now].lson = tr[last].lson , tr[now].rson = tr[last].rson;//先继承上一棵树再说
    	int mid =  (l+r)>>1;
    	if(x <= mid) tr[now].lson = insert(tr[last].lson , l, mid, x);
    	else tr[now].rson = insert(tr[last].rson , mid+1, r, x);
    	return now;
    }
    
    
    int query(int ltree, int rtree, int l, int r, int k) {//同时跳 //整体二分
    	if(l == r) return l;
    	int mid = (l+r)>>1;
    	int tmp = tr[tr[rtree].lson ].sum - tr[tr[ltree].lson ].sum ;
    	if(tmp >= k) return query(tr[ltree].lson , tr[rtree].lson , l, mid, k);
    	else return query(tr[ltree].rson , tr[rtree].rson , mid+1, r, k-tmp);
    }
    
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i = 1; i <= n; i++) scanf("%d",&a[i].a ), a[i].n = i;
    	sort(a+1, a+1+n, cmp1);
    	int tot = 0;
    	for(int i = 1; i <= n; i++) {
    		a[i].k = ++tot;
    		ys[tot] = a[i].a ;
    		while(a[i+1].a == a[i].a) a[++i].k = tot;
    	}
    	sort(a+1, a+1+n, cmp2);
    //	for(int i = 1; i <= n; i++) printf("
     lsh : %d
    ",a[i].k );
    	root[0] = build(1,n);
    	for(int i = 1;i <= n; i++)//边加点边建树 
    		root[i] = insert(root[i-1], 1, n, a[i].k) ; 
    	int ans, l, r, k; 
    	for(int i = 1; i <= m; i++) {
    		scanf("%d%d%d", &l, &r, &k);
    		ans = query(root[l-1], root[r], 1, n, k);
    		printf("%d
    ", ys[ans]);
    	}
    }
    
  • 相关阅读:
    mySQL安装的时候一直卡在starting server这里解决办法
    编译安装nginx
    用户访问网站原理及流程
    mysql备份及恢复
    sed
    mysql 基础
    nginx优化
    mysql 三种日志
    tr
    date
  • 原文地址:https://www.cnblogs.com/tyner/p/11253785.html
Copyright © 2011-2022 走看看