zoukankan      html  css  js  c++  java
  • 主席树进阶

    HDU-4348 To the moon

    Description

    You‘ve been given N integers A [1], A [2],..., A [N]. On these integers, you need to implement the following operations:
    1. C l r d: Adding a constant d for every {A i | l <= i <= r}, and increase the time stamp by 1, this is the only operation that will cause the time stamp increase.
    2. Q l r: Querying the current sum of {A i | l <= i <= r}.
    3. H l r t: Querying a history sum of {A i | l <= i <= r} in time t.
    4. B t: Back to time t. And once you decide return to a past, you can never be access to a forward edition anymore.
    .. N, M ≤ 10 5, |A [i]| ≤ 10 9, 1 ≤ l ≤ r ≤ N, |d| ≤ 10 4 .. the system start from time 0, and the first modification is in time 1, t ≥ 0, and won't introduce you to a future state.

    Input

    n m
    A 1 A 2 ... A n
    ... (here following the m operations. )

    Output

    ... (for each query, simply print the result. )

    Sample Input

    10 5
    1 2 3 4 5 6 7 8 9 10
    Q 4 4
    Q 1 10
    Q 2 4
    C 3 6 3
    Q 2 4
    
    2 4
    0 0
    C 1 1 1
    C 2 2 -1
    Q 1 2
    H 1 2 1
    

    Sample Output

    4
    55
    9
    15
    
    0
    1
    

    题解

    主席树+标记永久化,如果添加标记后每次都pushdown,对于主席树来说,每次pushdown都要新建一条链上的节点,如果pushdown我们的空间复杂度是不够的,所以我们要标记永久化,在查询的时候我们记录一下从根节点开始的标记是多少,每次统计答案时加上标记的贡献即可,回退版本时可以直接修改cnt为t+1版本的cnt,因为回退版本后不能返回,可以减少空间

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n, q;
    const int N = 1e5 + 10;
    ll a[N];
    int L[N * 30], R[N * 30], T[N];
    ll sum[N * 30];
    ll addv[N * 30];
    int cnt;
    void pushup(int rt, int l, int r) {
        sum[rt] = sum[L[rt]] + sum[R[rt]] + addv[rt] * (r - l + 1);
    }
    int build(int l, int r) {
        int rt = ++cnt;
        if (l == r) {
            sum[rt] = a[l];
            return rt;
        }
        int mid = (l + r) >> 1;
        if (l < r) {
            L[rt] = build(l, mid);
            R[rt] = build(mid + 1, r);
        }
        pushup(rt, l, r);
        return rt;
    }
    int update(int pre, int l, int r, int ql, int qr, ll v) {
        int rt = ++cnt;
        int mid = (l + r) >> 1;
        L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre], addv[rt] = addv[pre];
        if (ql <= l && r <= qr) {
            sum[rt] += (ll)(r - l + 1) * v;
            addv[rt] += v;
            return rt;
        }
        if (ql <= mid) L[rt] = update(L[pre], l, mid, ql, qr, v);
        if (qr > mid) R[rt] = update(R[pre], mid + 1, r, ql, qr, v);
        pushup(rt, l, r);
        return rt;
    }
    ll query(int rt, int l, int r, int ql, int qr, ll tot) {
        if (ql <= l && r <= qr) {
            return sum[rt] + tot * (r - l + 1);
        }
        tot += addv[rt];
        int mid = (l + r) >> 1;
        ll ans = 0;
        //pushdown(rt, l, r, L[rt], R[rt]);
        if (ql <= mid) ans += query(L[rt], l, mid, ql, qr, tot);
        if (qr > mid) ans += query(R[rt], mid + 1, r, ql ,qr, tot);
        return ans;
    }
    int main() {
        while (~scanf("%d%d", &n, &q)) {
            for (int i = 1; i <= n; i++) {
                scanf("%lld", &a[i]);
            }
            cnt = 0;
            memset(sum, 0, sizeof(sum));
            memset(addv, 0, sizeof(addv));
            T[0] = build(1, n);
            int now = 0;
            for (int i = 1; i <= q; i++) {
                char ch[2];
                int l, r; ll v;
                int t;
                scanf("%s", ch);
                if (ch[0] == 'Q') {
                    scanf("%d%d", &l, &r);
                    printf("%lld
    ", query(T[now], 1, n, l, r, 0));
                }
                if (ch[0] == 'C') {
                    scanf("%d%d%lld", &l, &r, &v);
                    now++;
                    T[now] = update(T[now - 1], 1, n, l, r, v);
                }
                if (ch[0] == 'H') {
                    scanf("%d%d%d", &l, &r, &t);
                    printf("%lld
    ", query(T[t], 1, n, l, r, 0));
                }
                if (ch[0] == 'B') {
                    scanf("%d", &t);
                    now = t;
                    cnt = T[now + 1];
                }
            }
        }
        return 0;
    }
    

    HDU-6278 Just (h)-index

    Description

    The (h)-index of an author is the largest (h) where he has at least (h) papers with citations not less than (h).

    Bobo has published (n) papers with citations (a_1, a_2, dots, a_n) respectively.
    One day, he raises (q) questions. The (i)-th question is described by two integers (l_i) and (r_i), asking the (h)-index of Bobo if has only published papers with citations (a_{l_i}, a_{l_i + 1}, dots, a_{r_i}).

    Input

    The input consists of several test cases and is terminated by end-of-file.

    The first line of each test case contains two integers (n) and (q).
    The second line contains (n) integers (a_1, a_2, dots, a_n).
    The (i)-th of last (q) lines contains two integers (l_i) and (r_i).

    Output

    For each question, print an integer which denotes the answer.

    ## Constraint

    * (1 leq n, q leq 10^5)
    * (1 leq a_i leq n)
    * (1 leq l_i leq r_i leq n)
    * The sum of (n) does not exceed (250,000).
    * The sum of (q) does not exceed (250,000).

    Sample Input

    5 3
    1 5 3 2 1
    1 3
    2 4
    1 5
    5 1
    1 2 3 4 5
    1 5
    

    Sample Output

    2
    2
    2
    3
    

    题解

    二分答案+主席树,水题

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n, m;
    const int N = 1e5 + 10;
    int a[N];
    int L[N * 20], R[N * 20], T[N];
    int sum[N * 20];
    int b[N];
    int cnt;
    int build(int l, int r) {
        int rt = ++cnt;
        sum[rt] = 0;
        int mid = (l + r) >> 1;
        if (l < r) {
            L[rt] = build(l, mid);
            R[rt] = build(mid + 1, r);
        }
        return rt;
    }
    int update(int pre, int l, int r, int x) {
        int rt = ++cnt;
        int mid = (l + r) >> 1;
        L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + 1;
        if (l < r) {
            if (x <= mid) L[rt] = update(L[pre], l, mid, x);
            else R[rt] = update(R[pre], mid + 1, r, x);
        }
        return rt;
    }
    int query(int u, int v, int l, int r, int k) {
        if (l >= r) return l;
        int mid = (l + r) >> 1;
        int x = sum[L[v]] - sum[L[u]];
        if (x >= k) return query(L[u], L[v], l, mid, k);
        else return query(R[u], R[v], mid + 1, r, k - x);
    }
    int main() {
        while (~scanf("%d%d", &n, &m)) {
            cnt = 0;
            for (int i = 1; i <= n; i++) {
                scanf("%d", &a[i]);
                b[i] = a[i];
            }
            sort(b + 1, b + n + 1);
            int cnt1 = unique(b + 1, b + n + 1) - b - 1;
            T[0] = build(1, cnt1);
            for (int i = 1; i <= n; i++) {
                a[i] = lower_bound(b + 1, b + cnt1 + 1, a[i]) - b;
                T[i] = update(T[i - 1], 1, cnt1, a[i]);
            }
            while (m--) {
                int x, y;
                scanf("%d%d", &x, &y);
                int l = 1, r = y - x + 1;
                int ans = 0;
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    if (b[query(T[x - 1], T[y], 1, cnt1, y - x + 2 - mid)] >= mid) {
                        ans = max(ans, mid);
                        l = mid + 1;
                    }
                    else r = mid - 1;
                }
                printf("%d
    ", ans);
            }
        }
        return 0;
    }
    

    HDU-5919 Sequence II

    Description

    Mr. Frog has an integer sequence of length n, which can be denoted as (a_1,a_2,cdots ,a_n) There are m queries.

    In the i-th query, you are given two integers (l_i) and (r_i). Consider the subsequence $a_{l_i},a_{l_{i+1}},a_{l_{i+2}},cdots ,a_{r_i} $.

    We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as (p_{1}^{(i)},p_{2}^{(i)},cdots, p_{k_i}^{(i)}) (in ascending order, i.e.,(p_{1}^{(i)}<p_{2}^{(i)}<cdots <p_{k_i}^{(i)})).

    Note that (k_i) is the number of different integers in this subsequence. You should output (p_{left lceil frac{k_i}{2} ight ceil}^{(i)})for the i-th query.

    Input

    In the first line of input, there is an integer T ((Tleq 2)) denoting the number of test cases.

    Each test case starts with two integers n ((n leq 2 imes 10^5)) and m ((mleq 2 imes 10^5)). There are n integers in the next line, which indicate the integers in the sequence(i.e., (a_1,a_2,cdots ,a_n, 0leq a_i leq 2 imes 10^5)).

    There are two integers (l_i) and (r_i) in the following m lines.

    However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to (l_i^`,r_i^`(1leq l_i^` leq n,1leq r_i^` leq n )). As a result, the problem became more exciting.

    We can denote the answers as (ans_1, ans_2,cdots ,ans_m). Note that for each test case (ans_0 = 0).

    You can get the correct input (l_i,r_i) from what you read (we denote them as (l_i^`,r_i^`))by the following formula:

    [l_i = min{ (l_i^`+ans_{i-1}) mod n+1, (r_i^`+ans_{i-1}) mod n+1 } ]

    [r_i = max{ (l_i^`+ans_{i-1}) mod n+1, (r_i^`+ans_{i-1}) mod n+1 } ]

    Output

    You should output one single line for each test case.

    For each test case, output one line “Case #x: (p_1,p_2,cdots ,p_m)”, where x is the case number (starting from 1) and (p_1,p_2,cdots ,p_m) is the answer.

    Sample Input

    2
    5 2
    3 3 1 5 4
    2 2
    4 4
    5 2
    2 5 2 1 2
    2 3
    2 4
    

    Sample Output

    Case #1: 3 3
    Case #2: 3 1
    

    Hint

    题解

    将主席树倒着插入,可以统计区间[l,r]的数的种类,具体方法是:

    维护一个pos数组,pos[a[i]]记录a[i]出现的最后的位置(倒着插入,即最靠左的位置),主席树则维护每一个位置有没有数,而不是以数的值为主席树下标。这样我们插入一个数时,如果pos[a[i]]==0,z,则直接在i位置+1,否则先将pos[a[i]]位置-1,再将i位置+1,这样区间端点(l)对应的主席树就维护了l之后的数的种数,我们只要查询[l,r]内有多少数就可以了,查询完之后再这颗树上求第((sum + 1) / 2)大的下标是多少就可以

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n, m;
    const int N = 2e5 + 100;
    int a[N];
    int L[N * 40], R[N * 40], T[N];
    int sum[N * 40];
    int cnt;
    int getnum() {
    	int ans = 0; char c;
    	while (!isdigit(c = getchar()));
    	ans = c - '0';
    	while (isdigit(c = getchar())) ans = ans * 10 + c - '0';
    	return ans;
    }
    int build(int l, int r) {
        int rt = ++cnt;
        sum[rt] = 0;
        int mid = (l + r) >> 1;
        if (l < r) {
            L[rt] = build(l, mid);
            R[rt] = build(mid + 1, r);
        }
        return rt;
    }
    int update(int pre, int l, int r, int x, int v) {
        int rt = ++cnt;
        int mid = (l + r) >> 1;
        L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + v;
        if (l < r) {
    		if (x <= mid) L[rt] = update(L[pre], l, mid, x, v);
    		else R[rt] = update(R[pre], mid + 1, r, x, v);
        }
        return rt;
    }
    int querysum(int rt, int l, int r, int ql, int qr) {
    	if (ql <= l && r <= qr) {
    		return sum[rt];
    	}
    	int mid = (l + r) >> 1;
    	int ans = 0;
    	if (ql <= mid) ans += querysum(L[rt], l, mid, ql, qr);
    	if (qr > mid) ans += querysum(R[rt], mid + 1, r, ql, qr);
    	return ans;
    }
    int queryk(int v, int l, int r, int k) {
        if (l >= r) return l;
        int mid = (l + r) >> 1;
        int x = sum[L[v]];
        if (x >= k) return queryk(L[v], l, mid, k);
        else return queryk(R[v], mid + 1, r, k - x);
    }
    int pos[N];
    int main() {
        int t;
        t = getnum();
        int cse = 0;
        //freopen("ans.txt", "w", stdout);
        while (t--) {
            n = getnum(), m = getnum();
            cnt = 0;
            for (int i = 1; i <= n; i++) {
                a[i] = getnum();
            }
            T[n + 1] = build(1, n);
            memset(pos, 0, sizeof(pos));
            for (int i = n; i >= 1; i--) {
    			if (!pos[a[i]]) {
    				T[i] = update(T[i + 1], 1, n, i, 1);
    				pos[a[i]] = i;
    			}
    			else {
    				T[i] = update(T[i + 1], 1, n, i, 1);
    				T[i] = update(T[i], 1, n, pos[a[i]], -1);
    				pos[a[i]] = i;
    			}
            }
            int ans = 0;
            cse++;
            printf("Case #%d:", cse);
            while (m--) {
                int l, r;
                l = getnum(), r = getnum();
                l = (l + ans) % n + 1;
                r = (r + ans) % n + 1;
                if (l > r) swap(l, r);
                int num = querysum(T[l], 1, n, l, r);
                printf(" %d", ans = queryk(T[l], 1, n, (num + 1) / 2));
            }
            printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    iptbales未完全删除或禁用的问题
    一键部署安装
    python表单流式上传gzip格式文件代码
    was进行jvm配置和GC收集
    Nginx心跳检测
    Python简单本地加解密
    vmware克隆虚拟机并设置网络(vcenter6或5.5)
    python操作mongodb数据库
    vue props传值后watch事件未触发的问题
    docker实战之通过nginx镜像来部署静态页
  • 原文地址:https://www.cnblogs.com/artoriax/p/11294800.html
Copyright © 2011-2022 走看看