Multi-University Training Contest 2 G - Naive Operations 线段树(区间查询+区间修改)

在写题之前先写给自己,线段树是一个完全二叉树,所以储存数据时用数组就足够方便了。然后上题。

In a galaxy far, far away, there are two integer sequence a and b of length n. 
b is a static permutation of 1 to n. Initially a is filled with zeroes. 
There are two kind of operations: 
1. add l r: add one for al,al+1...aral,al+1...ar 
2. query l r: query ∑ri=l⌊ai/bi⌋∑i=lr⌊ai/bi⌋

Input

There are multiple test cases, please read till the end of input file. 
For each test case, in the first line, two integers n,q, representing the length of a,b and the number of queries. 
In the second line, n integers separated by spaces, representing permutation b. 
In the following q lines, each line is either in the form 'add l r' or 'query l r', representing an operation. 
1≤n,q≤1000001≤n,q≤100000, 1≤l≤r≤n1≤l≤r≤n, there're no more than 5 test cases. 

Output

Output the answer for each 'query', each one line. 

Sample Input

5 12
1 5 2 4 3
add 1 4
query 1 4
add 2 5
query 2 5
add 3 5
query 1 5
add 2 4
query 1 4
add 2 5
query 2 5
add 2 2
query 1 5

Sample Output

1
1
2
4
4
6

【题意】有a,b两个数组a数组开始都为0,b数组则是给定的数。之后有两种操作add给定一个区间,将a数组区间内的数都加1.query a/b向上取整并在区间内求和。

【分析】由于查询次数过多直接暴搜必然超时,所以使用线段树来查询。然后我们再看查询时和的变化,a/b只有当a>b时才会使和增加。因此我们就不需要模拟a数组只需要模拟b数组同时在开一个c数组来充当区间和。每次add操作时给懒标记+1,b数组减1 。当b的值取0时在让c数组值加1 。最后query操作时只需要查询c数组就可以了。然后附上代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
 
using namespace std;
 
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
 
int B[maxn];
 
struct Tree {
    int b[maxn<<2], c[maxn<<2], lazy[maxn<<2];
    void init(int n) {
        for (int i = 0; i <= (n<<2); i++) b[i] = INF, c[i] = lazy[i] = 0;
    }
    void pushup(int root) {
        b[root] = min(b[root<<1], b[root<<1|1]);
        c[root] = c[root<<1] + c[root<<1|1];
    }
    void pushdown(int root) {
        if (lazy[root] == 0) return;
        lazy[root<<1] += lazy[root];
        lazy[root<<1|1] += lazy[root];
        b[root<<1] -= lazy[root];
        b[root<<1|1] -= lazy[root];
        lazy[root] = 0;
    }
    void build(int l, int r, int root) {
        if (l == r) {
            b[root] = B[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, root<<1);
        build(mid + 1, r, root<<1|1);
        pushup(root);
    }
    void update1(int l, int r, int root, int ul, int ur, int val) {
        if (ul <= l && r <= ur) {
            b[root] -= val;
            lazy[root] += val;
            return;
        }
        int mid = (l + r) >> 1;
        pushdown(root);
        if (ul <= mid) update1(l, mid, root<<1, ul, ur, val);
        if (mid < ur) update1(mid + 1, r, root<<1|1, ul, ur, val);
        pushup(root);
    }
    void update2(int l, int r, int root) {
        if (l == r) {
            b[root] = B[l];
            c[root]++;
            return;
        }
        int mid = (l + r) >> 1;
        pushdown(root);
        if (b[root<<1] == 0) update2(l, mid, root<<1);
        if (b[root<<1|1] == 0) update2(mid + 1, r, root<<1|1);
        pushup(root);
    }
    int query(int l, int r, int root, int ql, int qr) {
        if (ql <= l && r <= qr) return c[root];
        int mid = (l + r) >> 1;
        pushdown(root);
        int ans = 0;
        if (ql <= mid) ans += query(l, mid, root<<1, ql, qr);
        if (mid < qr) ans += query(mid + 1, r, root<<1|1, ql, qr);
        return ans;
    }
}tree;
 
int main() {
    int n, m;
    while (~scanf("%d%d", &n, &m)) {
        for (int i = 1; i <= n; i++) scanf("%d", &B[i]);
        tree.init(n);
        tree.build(1, n, 1);
        char s[10];
        int l, r;
        for (int i = 1; i <= m; i++) {
            scanf("%s%d%d", s, &l, &r);
            if (s[0] == 'a') {
                tree.update1(1, n, 1, l, r, 1);
                tree.update2(1, n, 1);
            }
            else {
                printf("%d\n", tree.query(1, n, 1, l, r));
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/happy_fakelove/article/details/81449656