E - Calc
题意:
举个栗子吧
abcde
要求的值就为
a ab abc abcd abcde b bc…之和
我们每修改一次某个值就要求一次和
我看到题就想到了线段树(我也不知道为什么)QWQ!!!
首先我打了一个线段树板子,只有一个t 数组 如果直接放进去
t 储存的值只是abced 中的一个段了,根本就不能求和。
要求和,先开个和的数组吧!反正也没什么用 ans数组(求和用的)
我们现在只有t 只能知道每个节点是abcde中的哪个段:
such as:abcde 是父亲 abc是儿子 de也是儿子,以此下分…
先画图一个图,如果想求ab这个节点的值怎么办呢,ANSab=a+b+ab,
那么ANSabc=a+b+c+ab+bc+abc,光是这两个值,是不可能单单用一个
t数组能解决的。
那怎么办?
如果能把儿子的节点的那些字母缀存起来就好了,对啊,就把它存起来!
比如:我们找ab节点以下的,1.a ab 2. b ba 我们得到了左右两个儿子节点的字母缀 推广一下 你就发现什么节点的和也能求出来了
用t1代表左边 ,t2代表右边 ,最底下的儿子 ANSa=a ANSb=b
ANSab = ANSa + ANSb + T1a T2b (ab)
那么t1为 T1=左边的儿子t *右边的儿子t1+左边的儿子t1
…t2类似…( 好像说的有点错误,但大概就是这个意思)
怎么说呢应该类似于多项式乘法吧,两边各记录 因子 相乘 即为这个节点的所有可能…
代码如下:
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define fo1(a,b) for(int a=0;a<b;++a)
#define fo2(a,b) for(int a=1;a<=b;++a)
#define inf 0x3f3f3f3f
#define S std::
using namespace std;
const int maxn=1e5+5;
const int mod=1e4+7;
int t[maxn<<2],t1[maxn<<2],t2[maxn<<2],ans[maxn<<2];
int n,m,a,b;
void pushup(int k){
t[k]=t[k<<1]*t[k<<1|1];
t1[k]=t1[k<<1|1]+t[k<<1|1]*t1[k<<1]%mod;
t2[k]=t2[k<<1]+t2[k<<1|1]*t[k<<1]%mod;
ans[k]=(ans[k<<1]+ans[k<<1|1])%mod+t1[k<<1]*t2[k<<1|1]%mod;
t[k]%=mod;
t1[k]%=mod;
t2[k]%=mod;
ans[k]%=mod;
}
void build(int k,int l,int r){
t[k]=0;
t1[k]=0;
t2[k]=0;
ans[k]=0;
if(l==r)
return ;
else{
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
}
void update(int k,int l,int r,int w,int v){
if(l==r&&l==w){
t[k]=v;
t1[k]=v;
t2[k]=v;
ans[k]=v;
}
else{
int mid=l+r>>1;
if(w<=mid)
update(k<<1,l,mid,w,v);
if(w>mid)
update(k<<1|1,mid+1,r,w,v);
pushup(k);
}
}
int main()
{
scanf("%d%d",&n,&m);
build(1,1,n);
fo2(i,m){
scanf("%d%d",&a,&b);
update(1,1,n,a,b);
printf("%d\n",ans[1]);
}
return 0;
}