描述
现在有一个有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
分析:如果提醒你前缀和后缀这两个字,自己差不多就都可以想到了。
解释一下前缀和后缀:
以1 2两个数为例
前缀:1, 1 2
后缀2, 1 2
以3 4两个数为例
前缀:3, 3 4
后缀4, 3 4
容易看出以1 2两个数为区间的区间和为 1 + 2 + 1*2, 以3 4两个数为区间的区间和为 3 + 4 + 3*4
如果以上述两个区间分别为左右子区间。那么 1 2 3 4区间
前缀 = 左子树前缀 + 左子树前缀中的最后一个 * 右子树前缀积和 即1 + 1*2 + (1*2)* (3 + 3*4)
后缀 = 右子树后缀 + 左子树后缀积和*右子树前缀的最后一个 即4 + 3*4 + (2+1 *2)* (3 * 4)
区间子段积和 = 左子树后缀 * 右子树前缀 + 左子树前缀+左子树后缀 - 左子树前缀与左子树后缀共有的一个数(即1*2) + 右子树前缀+右子树后缀 - 右子树前缀与右子树后缀共有的一个数(即3*4)
上面之所以要减去是因为我的这种做法,在加左子树前缀 与 左子树后缀 中加了1 * 2两遍
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 100005;
const int mod = 10007;
long long sum[maxn<<2];
int n, q;
struct Node
{
int left, right;
long long sum, pre, post, common;
}tree[maxn<<2];
void pushup(int rt)
{
tree[rt].pre = (tree[rt<<1].pre + tree[rt<<1].common*tree[rt<<1|1].pre) % mod;
tree[rt].post = (tree[rt<<1|1].post + tree[rt<<1].post*tree[rt<<1|1].common) % mod;
tree[rt].common = (tree[rt<<1].common * tree[rt<<1|1].common) % mod;
tree[rt].sum = (tree[rt<<1].post * tree[rt<<1|1].pre + tree[rt<<1].sum + tree[rt<<1|1].sum) % mod;
}
void build(int rt, int left, int right)
{
int mid = (left + right) >> 1;
tree[rt].left = left;
tree[rt].right = right;
if(left == right)
{
tree[rt].sum = tree[rt].pre = tree[rt].post = tree[rt].common = 0;
return ;
}
build(rt << 1, left, mid);
build(rt<<1|1, mid+1, right);
tree[rt].sum = tree[rt].pre = tree[rt].post = tree[rt].common = 0;
return ;
}
void modify(int rt, int pos, long long val)
{
if(pos < tree[rt].left || pos > tree[rt].right)
return ;
if(tree[rt].left == pos && tree[rt].right == pos)
{
tree[rt].sum = tree[rt].pre = tree[rt].post = tree[rt].common = val % mod;
return ;
}
modify(rt<<1, pos, val);
modify(rt<<1|1, pos, val);
pushup(rt);
return ;
}
int main()
{
while(scanf("%d%d", &n, &q) != EOF)
{
memset(tree, 0, sizeof(tree));
build(1, 1, n);
int pos; long long val;
for(int i = 1; i <= q; i++)
{
scanf("%d%lld", &pos, &val);
modify(1, pos, val);
printf("%lld\n", tree[1].sum % mod);
}
}
return 0;
}