zoukankan      html  css  js  c++  java
  • 算法笔记--可持久化线段树

    参考:https://www.cnblogs.com/RabbitHu/p/segtree.html

    模板:

    const int N = 1e5 + 5, M = 2e6 + 5;//M为节点个数,为Q*log(N)
    int root[N], lson[M], rson[M], value[M], tot = 0;
    //建树
    void build(int &x, int l, int r) {
        x = ++tot;
        if(l == r) {
            scanf("%d", &value[x]);
            return ;
        }
        int m = (l+r) >> 1;
        build(lson[x], l, m);
        build(rson[x], m+1, r);
        value[x] = value[lson[x]] + value[rson[x]];
    }
    // 将某个历史版本p位置的值加v
    void update(int old, int &x, int p, int v, int l, int r) {
        x = ++tot;
        lson[x] = lson[old], rson[x] = rson[old], value[x] = value[old] + v;
        if(l == r) return ;
        int m = (l+r) >> 1;
        if(p <= m) update(lson[x], lson[x], p, v, l, m);
        else update(rson[x], rson[x], p, v, m+1, r);
    }
    //访问某个历史版本L到R的区间和
    int query(int L, int R, int x, int l, int r) {
        if(L <= l && r <= R) return value[x];
        int m = (l+r) >> 1, ans = 0;
        if(L <= m) ans += query(L, R, lson[x], l, m);
        if(R > m) ans += query(L, R, rson[x], m+1, r);
        return ans;
    }

     1175 区间中第K大的数

    思路:

    将求第k小的问题的问题转换成权值统计问题,采用可持久化线段树维护

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize(4)
    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define pi acos(-1.0)
    #define LL long long
    //#define mp make_pair
    #define pb push_back
    #define ls rt<<1, l, m
    #define rs rt<<1|1, m+1, r
    #define ULL unsigned LL
    #define pll pair<LL, LL>
    #define pii pair<int, int>
    #define piii pair<pii, int>
    #define mem(a, b) memset(a, b, sizeof(a))
    #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);
    //head
    
    const int N = 5e4 + 5, M = 2e6 + 5;//M为节点个数,为Q*log(N)
    int root[N], lson[M], rson[M], value[M], tot = 0;
    int a[N], v[N];
    vector<int>vc;
    void build(int &x, int l, int r) {
        x = ++tot;
        if(l == r) {
            value[x] = 0;
            return ;
        }
        int m = (l+r) >> 1;
        build(lson[x], l, m);
        build(rson[x], m+1, r);
        value[x] = value[lson[x]] + value[rson[x]];
    }
    void update(int old, int &x, int p, int v, int l, int r) {
        x = ++tot;
        lson[x] = lson[old], rson[x] = rson[old], value[x] = value[old] + v;
        if(l == r) return ;
        int m = (l+r) >> 1;
        if(p <= m) update(lson[x], lson[x], p, v, l, m);
        else update(rson[x], rson[x], p, v, m+1, r);
    }
    int query(int x, int y, int l, int r, int k) {
        if(l == r) return l;
        int m = (l+r) >> 1, cnt = value[lson[y]] - value[lson[x]];
        if(k <= cnt) return query(lson[x], lson[y], l, m, k);
        else return query(rson[x], rson[y], m+1, r, k-cnt);
    }
    int main() {
        int n, l, r, k, q;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]), vc.pb(a[i]);
        sort(vc.begin(), vc.end());
        vc.erase(unique(vc.begin(), vc.end()), vc.end());
        for (int i = 1; i <= n; i++) {
           int id = lower_bound(vc.begin(), vc.end(), a[i]) - vc.begin() + 1;
           v[id] = a[i];
           a[i] = id;
        }
        build(root[0], 1, n);
        for (int i = 1; i <= n; i++) {
            update(root[i-1], root[i], a[i], 1, 1, n);
        }
        scanf("%d", &q);
        while(q--) {
            scanf("%d %d %d", &l, &r, &k); 
            //cout << query(root[l], root[r+1], 1, n, (r-l+1-k+1)) << endl;
            printf("%d
    ", v[query(root[l], root[r+1], 1, n, (r-l+1-k+1))]);
        }
        return 0;
    }
    View Code

    2112

    思路:

    树状数组套可持久线段树,注意一开始要建静态主席树,否则会爆栈

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize(4)
    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define pi acos(-1.0)
    #define LL long long
    //#define mp make_pair
    #define pb push_back
    #define ls rt<<1, l, m
    #define rs rt<<1|1, m+1, r
    #define ULL unsigned LL
    #define pll pair<LL, LL>
    #define pii pair<int, int>
    #define piii pair<pii, int>
    #define mem(a, b) memset(a, b, sizeof(a))
    #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);
    //head
    
    const int N = 5e4 + 5, M = 1e4 + 5;
    int a[N], root[N], bitroot[N], value[N*40], lson[N*40], rson[N*40], use[N], tot, up, n;
    piii Q[M];
    vector<int>vc;
    char s[M][10];
    void build(int &x, int l, int r) {
        x = ++tot;
        if(l == r) {
            value[x] = 0;
            return ;
        }
        int m = l+r >> 1;
        build(lson[x], l, m);
        build(rson[x], m+1, r);
        value[x] = value[lson[x]] + value[rson[x]];
    }
    int update(int old, int &x, int p, int v, int l, int r) {
        x = ++tot;
        lson[x] = lson[old], rson[x] = rson[old], value[x] = value[old] + v;
        if(l == r) return 0;
        int m = l+r >> 1;
        if(p <= m) update(lson[old], lson[x], p, v, l, m);
        else update(rson[old], rson[x], p, v, m+1, r);
        return 0;
    }
    void add(int x, int pos, int v) {
        while(x <= n) {
            update(bitroot[x], bitroot[x], pos, v, 1, up);
            x += x&-x;
        }
    }
    int sum(int x) {
        int ans = 0;
        while(x) {
            ans += value[lson[use[x]]];
            x -= x&-x;
        }
        return ans;
    }
    int query(int l, int r, int k) {
        for (int i = l-1; i; i -= i&-i) use[i] = bitroot[i];
        for (int i = r; i; i -= i&-i) use[i] = bitroot[i];
        int lroot = root[l-1], rroot = `root[r];
        int ll = 1 , rr = up, m = ll+rr >> 1;
        while(ll < rr) {
            int cnt = sum(r) - sum(l-1) + value[lson[rroot]] - value[lson[lroot]];
            if(k <= cnt) {
                rr = m;
                for (int i = l-1; i; i -= i&-i) use[i] = lson[use[i]];
                for (int i = r; i; i -= i&-i) use[i] = lson[use[i]];
                lroot = lson[lroot];
                rroot = lson[rroot];
            }
            else {
                ll = m+1;
                k -= cnt;
                for (int i = l-1; i; i -= i&-i) use[i] = rson[use[i]];
                for (int i = r; i; i -= i&-i) use[i] = rson[use[i]];
                lroot = rson[lroot];
                rroot = rson[rroot];
            }
            m = ll+rr >> 1;
        }
        return ll;
    }
    int main() {
        int T, m;
        scanf("%d", &T);
        while(T--) {
            scanf("%d %d", &n, &m);
            vc.clear();
            for (int i = 1; i <= n; i++) scanf("%d", &a[i]), vc.pb(a[i]);
            for (int i = 0; i < m; i++) {
                scanf("%s", s[i]);
                if(s[i][0] == 'Q') {
                    scanf("%d %d %d", &Q[i].fi.fi, &Q[i].fi.se, &Q[i].se);
                }
                else {
                    scanf("%d %d", &Q[i].fi.fi, &Q[i].fi.se);
                    vc.pb(Q[i].fi.se);
                }
            }
            sort(vc.begin(), vc.end());
            vc.erase(unique(vc.begin(), vc.end()), vc.end());
    
            up = (int)vc.size();
            tot = 0;
            build(root[0], 1, up);
            for (int i = 1; i <= n; i++) a[i] = lower_bound(vc.begin(), vc.end(), a[i]) - vc.begin() + 1;
            for (int i = 1; i <= n; i++) update(root[i-1], root[i], a[i], 1, 1, up);//要开静态主席树,否则会爆栈,SegmentFault一整天
            for (int i = 1; i <= n; i++) bitroot[i] = root[0];//树状数组每个点对应一个权值线段树,要单独开
            for (int i = 0; i < m; i++) {
                if(s[i][0] == 'Q') printf("%d
    ", vc[query(Q[i].fi.fi, Q[i].fi.se, Q[i].se) - 1]);
                else {
                    add(Q[i].fi.fi, a[Q[i].fi.fi], -1);
                    int t = lower_bound(vc.begin(), vc.end(), Q[i].fi.se) - vc.begin() + 1;
                    add(Q[i].fi.fi, t, 1);
                    a[Q[i].fi.fi] = t;
                }
            }
        }
        return 0;
    }
    /*
    2
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    */
    View Code
  • 相关阅读:
    01Angular开发环境配置
    不再显示广告案例(php操作cookie)
    php操作 cookie
    JPush Android 推送如何区分开发、生产环境
    10 分钟实现一个自己的服务器监控器
    iOS 轻松使用 App 数据统计
    认识本质:黑天鹅、关键时刻与张小龙的产品观
    C# 服务端推送,十步十分钟,从注册到推送成功
    聊天界面-自适应文字
    极光推送的角标问题——让人又爱又恨的小红点
  • 原文地址:https://www.cnblogs.com/widsom/p/9414836.html
Copyright © 2011-2022 走看看