题意:

给n个位置,q次操作,每次对操作可以改变i位置的数,定义2020NYIST个人积分赛第四场(线段树+前缀 后缀乘积和)_ios

题解

主要难点是找到求所有子区间乘积和的规律,然后用线段树维护。通过找规律,可以发现,所求所有子区间的和为该节点左儿子的和+该节点右儿子的和+左儿子的后缀乘积和*右儿子的前缀乘积和。

开一个结构体,每个节点带四个信息:

struct node
{
int mul; 区间乘积
int qs; 前缀和
int hs; 后缀和
int sum; 区间和
}

我们可以通过区间乘积来维护区间前后缀的乘积和

维护代码:

void pushup(ll k)
{
tr[k].mul=(tr[k<<1].mul*tr[k<<1|1].mul)%mod;
tr[k].sum=((tr[k<<1].sum+tr[k<<1|1].sum)%mod+(tr[k<<1].hs*tr[k<<1|1].qs)%mod)%mod;
tr[k].qs=(tr[k<<1].qs+(tr[k<<1].mul*tr[k<<1|1].qs)%mod)%mod;
tr[k].hs=(tr[k<<1|1].hs+(tr[k<<1|1].mul*tr[k<<1].hs%mod))%mod;
}

参考代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e6+5;
const ll mod=10007;
struct node
{
ll mul,qs,hs,sum;
}tr[maxn<<2];
void pushup(ll k)
{
tr[k].mul=(tr[k<<1].mul*tr[k<<1|1].mul)%mod;
tr[k].sum=((tr[k<<1].sum+tr[k<<1|1].sum)%mod+(tr[k<<1].hs*tr[k<<1|1].qs)%mod)%mod;
tr[k].qs=(tr[k<<1].qs+(tr[k<<1].mul*tr[k<<1|1].qs)%mod)%mod;
tr[k].hs=(tr[k<<1|1].hs+(tr[k<<1|1].mul*tr[k<<1].hs%mod))%mod;
}
void inser(ll k,ll l,ll r,ll pos,ll w)
{
if(l==r)
{
tr[k].sum=tr[k].mul=tr[k].qs=tr[k].hs=w%mod;
return ;
}
ll mid=l+r>>1;
if(mid>=pos)
inser(k<<1,l,mid,pos,w);
else
inser(k<<1|1,mid+1,r,pos,w);
pushup(k);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
ll n,q;
cin>>n>>q;
while(q--)
{
ll pos,w;
cin>>pos>>w;
inser(1,1,n,pos,w);
cout<<(tr[1].sum%mod)<<endl;
}
}