描述
现在有一个有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
考虑用线段树解决。设sumv[o]表示区间[l,r]的答案,那么首先sumv[o]=sumv[lc]+sumv[rc],加上跨越中线的答案即可。
用ls[o]表示后缀的乘积之和,rs[o]表示前缀的乘积之和,维护一下即可。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } typedef long long ll; const int maxn=100010; const int mod=10007; ll sumv[maxn*3],ls[maxn*3],rs[maxn*3],xp[maxn*3]; void update(int o,int l,int r,int x,ll v) { if(l==r) ls[o]=rs[o]=sumv[o]=xp[o]=v; else { int mid=l+r>>1,lc=o<<1,rc=lc|1; if(x<=mid) update(lc,l,mid,x,v); else update(rc,mid+1,r,x,v); xp[o]=(xp[lc]*xp[rc])%mod; sumv[o]=(sumv[lc]+sumv[rc]+ls[rc]*rs[lc])%mod; ls[o]=(ls[lc]+ls[rc]*xp[lc])%mod; rs[o]=(rs[rc]+rs[lc]*xp[rc])%mod; } } int main() { int n=read(),m=read(); while(m--) { int x=read(),v=read(); update(1,1,n,x,v); printf("%lld ",sumv[1]); } return 0; }