您的位置:首页 > 其它

hihoCoder#1116-计算[线段树+合并区间]

2017-03-21 16:55 337 查看
时间限制:4000ms
单点时限:1000ms
内存限制:256MB


描述

现在有一个有n个元素的数组a1, a2,
..., an。
记f(i, j) = ai * ai+1 *
... * aj。
初始时,a1 = a2 =
... = an = 0,每次我会修改一个ai的值,你需要实时反馈给我
∑1 <= i <= j <= n f(i, j)的值 mod 10007。


输入

第一行包含两个数n(1<=n<=100000)和q(1<=q<=500000)。
接下来q行,每行包含两个数i, x,代表我把ai的值改为了x。


输出

分别输出对应的答案,一个答案占一行。

样例输入
5 5
1 1
2 1
3 1
4 1
5 1


样例输出
1
3
6
10
15


题意:求所有子区间乘积之和。

思路:线段树可在logn时间复杂度内完成对区间的修改与查询。不过,这道题要定义一个数据结构
struct Node {
int l, r;
_long all, lseg, rseg, mul;
}

all:题目答案,lseg:区间所有前缀乘积之和,rseg:区间所有后缀乘积之和,mul:区间所有元素乘积。下面请看一组例子加深对本数据结构的理解。
例:
[3 4 2 5]
all:3 + 3*4 + 4*2 + 2*5 + 3*4*2 + 4*2*5 + 3*4*2*5
lseg:3 + 3*4 + 3*4*2 + 3*4*2*5
rseg:3*4*2*5 + 4*2*5 + 2*5 + 5
mul:3*4*2*5
那么,区间是这样合并的:
a[rt].all = (a[rt << 1].all + a[(rt << 1) | 1].all + a[rt << 1].rseg * a[(rt << 1) | 1].lseg) % MOD;
a[rt].lseg = (a[rt << 1].lseg + a[rt << 1].mul * a[(rt << 1) | 1].lseg) % MOD;
a[rt].rseg = (a[(rt << 1) | 1].rseg + a[(rt << 1) | 1].mul * a[rt << 1].rseg) % MOD;
a[rt].mul = (a[rt << 1].mul * a[(rt << 1) | 1].mul) % MOD;

下面是AC代码:
#include <cstdio>
using namespace std;
const int MAXN = 100005;
const int MOD = 10007;
typedef long long _long;
struct Node { int l, r; _long all, lseg, rseg, mul; }a[MAXN * 3];
int n, q;

void pushUp(int rt) {
a[rt].all = (a[rt << 1].all + a[(rt << 1) | 1].all + a[rt << 1].rseg * a[(rt << 1) | 1].lseg) % MOD; a[rt].lseg = (a[rt << 1].lseg + a[rt << 1].mul * a[(rt << 1) | 1].lseg) % MOD; a[rt].rseg = (a[(rt << 1) | 1].rseg + a[(rt << 1) | 1].mul * a[rt << 1].rseg) % MOD; a[rt].mul = (a[rt << 1].mul * a[(rt << 1) | 1].mul) % MOD;
}

void build(int rt, int l, int r) {
a[rt].l = l;
a[rt].r = r;
if (l == r) {
a[rt].all = a[rt].lseg = a[rt].rseg = a[rt].mul = 0;
return ;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build((rt << 1) | 1, mid + 1, r);
pushUp(rt);
}

void update(int rt, int pos, long val) {
if (a[rt].l == pos && a[rt].r == pos) {
a[rt].all = a[rt].lseg = a[rt].rseg = a[rt].mul = val;
return ;
}
int mid = (a[rt].l + a[rt].r) >> 1;
if (pos <= mid) {
update(rt << 1, pos, val);
} else {
update((rt << 1) | 1, pos, val);
}
pushUp(rt);
}

int main() {
while (scanf("%d%d", &n, &q) != EOF) {
build(1, 1, n);
while (q--) {
int pos;
_long x;
scanf("%d%lld", &pos, &x);
update(1, pos, x % MOD);
printf("%lld\n", a[1].all);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: