很可做的一道题
考虑一下一段序列的答案为b+x,x为最右连续一段是乘积,然后和为x,b则为对应的左边的和
然后考虑在右边加一个数k,分类讨论一下发现x'=kx,b'=2x+3b
于是就可以DP了
然后DP可以矩阵转移
于是就可以用线段树维护矩阵
就水过去了
(好像很简单哎,AC率好高的说)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<ctime>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define mmt(a,v) memset(a,v,sizeof(a))
#define tra(i,u) for(int i=head[u];i;i=e[i].next)
using namespace std;
typedef long long ll;
const int N=100000+5;
const int P=(1e9)+7;
struct matrix{
ll a[2][2];
void clr(){mmt(a,0);}
matrix operator * (matrix &b){
static matrix c;c.clr();
rep(i,0,1)rep(j,0,1)rep(k,0,1)
c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j])%P;
return c;
}
};
struct Node{
int l,r;
matrix t;
}tr[N<<2];
#define lc o<<1
#define rc o<<1|1
void pushup(int o){tr[o].t=tr[lc].t*tr[rc].t;}
void update(int o,int p,int v){
int l=tr[o].l,r=tr[o].r;
if(l==r)tr[o].t.a[0][0]=v;
else{
int mid=l+r>>1;
if(p<=mid)update(lc,p,v);
else update(rc,p,v);
pushup(o);
}
}
int a[N];
void build(int o,int l,int r){
tr[o].l=l;tr[o].r=r;
if(l==r){
if(l==1)tr[o].t.a[0][0]=a[l];
else{
tr[o].t.a[0][0]=a[l];tr[o].t.a[0][1]=2;
tr[o].t.a[1][0]=0;tr[o].t.a[1][1]=3;
}
}else{
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
pushup(o);
}
}
int main(){
//freopen("a.in","r",stdin);
int n,q;scanf("%d%d",&n,&q);
rep(i,1,n)scanf("%d",&a[i]);
build(1,1,n);
while(q--){
int p,v;scanf("%d%d",&p,&v);
update(1,p,v);
printf("%lld\n",(tr[1].t.a[0][0]+tr[1].t.a[0][1])%P);
}
return 0;
}