• 洛谷 P3834 【【模板】可持久化线段树 1(主席树)】


    主席树模板题。
    首先我不认为这是什么很高级的数据结构,如果你已经对线段树掌握的很熟练的话应该不难理解主席树。

    正文部分:

    主席树一般用来解决静态区间的第(k)小问题。

    原理:

    首先我们可以在纸上画一张空的线段树。然后我们加入某个节点的时候你们就在纸上与这个节点所相关的节点的值就加(1)
    比如我们加入了值(1),那么受到影响的区间就有:([1,7],[1,4],[1,2],[1,1])
    好,当我们把所有的点都加完了之后,接下来就要解决第(k)小的问题。
    先假设我们查的区间为([l,r])那么我们就将第(l)颗线段树与第(r)颗线段树相减。其中所有节点所得的差就是某段区间里的值得个数。
    然后我们就可以查了。如果某段区间中的值得个数大于(k),我们就往左子树走,否则就减掉左子树,然后往右子树走。

    My Code:

    #include <bits/stdc++.h>
    #define il inline
    const int MAXN = 2e5 + 10;
    using namespace std;   
    int n,m,i,j,k,cnt;
    int a[MAXN],lsh[MAXN];
    int num[MAXN << 5],l[MAXN << 5],r[MAXN << 5],sum[MAXN << 5];
    template<typename T> il void read(T& res) {
        res = 0;char c;bool sign = 0;
        for(c = getchar();!isdigit(c);c = getchar()) sign |= c == '-';
        for(;isdigit(c);c = getchar()) res = (res << 1) + (res << 3) + (c ^ 48);
        (sign) && (res = -res);
        return;
    }
    int build(int l,int r) {
        cnt++;int num = cnt;
        if(l < r) {
            int mid = l + r >> 1;
            ::l[num] = build(l,mid);
            ::r[num] = build(mid + 1,r);
        }
        return num;
    }
    int modify(int pre,int l,int r,int mn) {
        cnt++;int num = cnt;
        ::l[num] = ::l[pre];::r[num] = ::r[pre];::sum[num] = ::sum[pre] + 1;
        if(l < r) {
            int mid = l + r >> 1;
            if(mn <= mid) ::l[num] = modify(::l[pre],l,mid,mn);
            else ::r[num] = modify(::r[pre],mid + 1,r,mn);
        }
        return num;
    }
    int query(int x,int y,int l,int r,int k) {
        if(l >= r) return l;
        int tmp = ::sum[::l[y]] - ::sum[::l[x]];
        int mid = l + r >> 1;
        if(tmp >= k) return query(::l[x],::l[y],l,mid,k);
        else return query(::r[x],::r[y],mid + 1,r,k - tmp);
    }
    int main() {
        read(n);read(m);
        for(int i = 1;i <= n;i++) {
            read(a[i]);lsh[i] = a[i];
        }	
        sort(lsh + 1,lsh + n + 1);int _n = unique(lsh + 1,lsh + n + 1) - lsh - 1;
        num[0] = build(1,_n);
        for(int i = 1;i <= n;i++) {
            int tmp = lower_bound(lsh + 1,lsh + _n + 1,a[i]) - lsh;
            num[i] = modify(num[i - 1],1,_n,tmp);
        }
    //	for(int i = 0;i <= n;i++) cout << num[i] << ' ';cout << endl;
        for(int i = 1;i <= m;i++) {
            int l,r,k;read(l);read(r);read(k);
            int tmp = query(num[l - 1],num[r],1,_n,k);        
            printf("%d
    ",lsh[tmp]);
        }
        return 0;
    }
    
  • 相关阅读:
    Facebook第三方登录切换账号的问题
    内部类中调用外部变量
    前端还原UI设计图CSS样式工具(ps+蓝湖+PxCook+imgcook)
    git 报错 eslint fix found some errors. Please fix them and try committing again.
    在vue中使用vuebaidumap实现地址定位标点及关键字搜索定位(获取地址数据并获取经纬度)
    elementui的时间范围组件,限制选了第一个时间后,第二个只能在第一个的前后一周
    JavaScript API v2.0+ v3.0
    BFC块级格式化上下文
    解决小程序api无法返回promise对象
    移动端适配 视口(viewport)和vw、vh、rem
  • 原文地址:https://www.cnblogs.com/Sai0511/p/10360356.html
Copyright © 2020-2023  润新知