• Luogu SP3267 Dquery(主席树)


    SP3267 D-query

    题目大意:

    给出长度为 \(n\) 的序列,\(q\) 次询问,每次为区间 \([l, r]\) 有多少不同的数字。

    思路:

    显然可以用莫队解决,考虑带 log 的做法。

    对于一个区间 \([l, r]\) 来说,区间内若有重复出现的数,那么他上一次出现的位置除了第一次出现的数以外,都在 \([l, r]\) 范围内。我们记录每个位置上的值上一次出现的位置为 \(last[i]\) ,问题转化为求 \([l, r]\)\(last[i] < l\) 的个数。区间上的权值线段树,使用主席树解决。

    Code:
    struct Node { //每个点维护的是值域上值的个数
        int lf, rt;
        ll sum; //该节点的左节点为hjt[lf],右节点为hjt[rt],值为sum
    } hjt[N * 40];
    int tot = 0, root[N];
    //pre的作用是now要依赖以上一个版本的权值线段树来建立
    void insert(int l, int r, int pre, int &now, ll p) {
        hjt[++tot] = hjt[pre]; //等于上一个版本线段树的当前节点
        now = tot;
        ++hjt[now].sum;
        if (l == r) return;
        int m = (l + r) >> 1;
        if (p <= m) insert(l, m, hjt[pre].lf, hjt[now].lf, p);
        else insert(m + 1, r, hjt[pre].rt, hjt[now].rt, p);
    }
    //搜索到的当前节点所维护的区间为[l, r]
    //我们当前要查询[L, R]的权值线段树,Lnow表示L - 1版本的权值线段树遍历到的当前节点,Rnow表示R版本的权值线段树遍历到的当前节点
    ll query(int l, int r, int Lnow, int Rnow, int ql, int qr) {
        if (ql <= l && r <= qr) {
            return hjt[Rnow].sum - hjt[Lnow].sum;
        }
        int m = (l + r) >> 1;
        ll ans = 0;
        if (ql <= m)
            ans += query(l, m, hjt[Lnow].lf, hjt[Rnow].lf, ql, qr);
        if (qr > m)
            ans += query(m + 1, r, hjt[Lnow].rt, hjt[Rnow].rt, ql, qr);
        return ans;
    }
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int n, m;
        cin >> n;
        vector<int> a(n + 1);
        vector<int> pre(N, 0);
        vector<int> las(n + 1);
        for (ll i = 1; i <= n; i++) {
            cin >> a[i];
            las[i] = pre[a[i]] + 1; //整体向右偏移一位
            pre[a[i]] = i;
            insert(1, n, root[i - 1], root[i], las[i]);
        }
        cin >> m;
        for (ll i = 1, l, r; i <= m; i++) {
            cin >> l >> r;
            cout << query(1, n, root[l - 1], root[r], 1, l) << "\n";
        }
        return 0;
    }
    
  • 相关阅读:
    堆排序算法
    二叉树的创建、遍历(递归和非递归实现)、交换左右子数、求高度(c++实现)
    hdoj1010 奇偶剪枝+DFS
    常见排序算法c++总结
    B
    C
    D
    E
    G
    F
  • 原文地址:https://www.cnblogs.com/Nepenthe8/p/15999621.html
Copyright © 2020-2023  润新知