hihoCoder - 1116 - 计算 (线段树)

计算

题目传送:#1116 : 计算

这里说下sum,pre,suf,ji数组的含义:

sum:所求答案
pre:所有前缀积之和
suf:所有后缀积之和
ji:区间内所有数之积

以一个例子说明:

比如我们现在正在合并区间{3,4},{2,5}

而区间{3,4}所表示的

sum1=3 + 4 + 3 * 4 = 19
pre1 = 3 + 3 * 4 = 12
suf1 = 3 * 4 + 4 = 16
ji1 = 3 * 4 = 12

而区间{2,5}

sum2 = 2 + 5 + 2 * 5 = 17
pre2 = 2 + 2 * 5 = 12
suf2 = 2 * 5 + 5 = 15
ji2 = 2 * 5 = 10

合并的时候:

sum = sum1 + sum2 + 3 * 4 * 2 + 3 * 4 * 2 * 5 + 4 * 2 + 4 * 2 * 5
即sum = sum1 + sum2 + suf1 * pre2

不过也要同时记得更新ji,pre和suf数组

AC代码:

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;

#define MOD 10007

int n, q;

const int maxn = 100005;
int sum[maxn << 2];//此节点所表示区间内的所有子序列的乘积之和,即输出答案为sum[1]
int ji[maxn << 2];//此节点所表示区间内各个数之积
int pre[maxn << 2];//此节点所表示的区间处于合并时的后缀时所对合并后的区间的贡献
int suf[maxn << 2];//此节点所表示的区间处于合并时的前缀时所对合并后的区间的贡献

void pushup(int rt, int m) {
    ji[rt] = ji[rt << 1] * ji[rt << 1 | 1] % MOD;
    sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1] + suf[rt << 1] * pre[rt << 1 | 1]) % MOD;
    pre[rt] = (pre[rt << 1] + ji[rt << 1] * pre[rt << 1 | 1]) % MOD;
    suf[rt] = (suf[rt << 1 | 1] + ji[rt << 1 | 1] * suf[rt << 1]) % MOD;
}

void build(int rt, int l, int r) {
    sum[rt] = 0;
    pre[rt] = 0;
    suf[rt] = 0;
    ji[rt] = 0;
    if(r == l) {
        return;
    }
    int mid = (l + r) >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r); 
}

void update(int rt, int l ,int r, int p, int x) {
    if(l == r && l == p) {
        sum[rt] = x % MOD;
        pre[rt] = x % MOD;
        suf[rt] = x % MOD;
        ji[rt] = x % MOD;
        return;
    }
    int mid = (l + r) >> 1;
    if(p <= mid) update(rt << 1, l, mid, p, x);
    else update(rt << 1 | 1, mid + 1, r, p, x);
    pushup(rt, r - l + 1);
}

int main() {
    scanf("%d %d", &n, &q);
    build(1, 1, n);
    for(int i = 0; i < q; i ++) {
        int p, x;
        scanf("%d %d", &p, &x); 
        update(1, 1, n, p, x);
        printf("%d\n", sum[1]);
    }
    return 0;
}

你可能感兴趣的:(线段树,ACM,hihoCoder)