题目链接:http://acm.csust.edu.cn/problem/4005
博客园食用链接:https://blog.csdn.net/qq_43906000/article/details/107815634
Description
给一个长度(n)的序列(a_i) 要进行(m)次操作,共有三种操作:
(1.(L;R;V)) 表示区间([L,R])数值覆盖为(V);
(2.(P;V))表示(a_p) 数值赋值为(V);
(3.(L;R))表示询问询问(f(L,R))的值。
注意:
对于区间([L,R])的数字而言,(S_i)=在区间内任意选ii个数的乘积之和。
(f(L,R)=(1+sum_{i=1}^{R-L+1}S_i)mod; 1e9+9)
Input
一行两个整数(n,m(1le n,mle 2e5))
接下来一行(n)个整数表示(a_i(0le a_ile 1e9))
接下来(m)行表示(m)次操作:
输入格式为:
(1;L;R;V, 1le Lle Rle n, 0le Vle 1e9)
(2;P;V,1le Ple n,0le Vle 1e9)
(3;L;R,(1le Lle Rle n))
Output
对每次(3)号操作输出一行一个整数表示答案。答案要对(1e9+9)取模。
emmm,说是个签到题来着。。。如果单纯地盯着上面的(f(L,R)=(1+sum_{i=1}^{R-L+1}S_i)mod; 1e9+9)这一串式子,肯定是没有什么眉目的,我们看题目要求应该大概是个线段树,那么我们只需要考虑的是在线段树中将两颗子树合并后的结果和区间覆盖后的结果。那么对于每个节点,我们保存的值假设就是(val+1),那么我们考虑合并(x,y)两个值,他们合并之后就是(xy+x+y+1),可以看出就是两个数相乘加上两个数相加,那么似乎就是((x+1)*(y+1)),于是我们会惊讶地发现父节点的值就是两个儿子节点的乘积!
接下来就是对于区间覆盖的处理了,那么就相当于(r-l+1)个(x)的合并,那么就是((x+1)^{r-l+1})。似乎这题就结束了。
以下是AC代码:
#include <bits/stdc++.h>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lc rt<<1
#define rc rt<<1|1
typedef long long ll;
const int mac=2e5+10;
const int mod=1e9+9;
ll tree[mac<<2],lazy[mac<<2];
ll qpow(ll a,ll b)
{
ll ans=1; a%=mod;
while (b){
if (b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void build(int l,int r,int rt)
{
lazy[rt]=-1;
if (l==r) {
scanf ("%d",&tree[rt]);
tree[rt]++;
return;
}
int mid=(l+r)>>1;
build(lson); build(rson);
tree[rt]=tree[lc]*tree[rc]%mod;
}
void push_down(int l,int r,int rt)
{
int mid=(l+r)>>1;
lazy[lc]=lazy[rt]; lazy[rc]=lazy[rt];
tree[lc]=qpow(lazy[rt],mid-l+1); tree[rc]=qpow(lazy[rt],r-mid);
lazy[rt]=-1;
}
void update(int l,int r,int rt,int L,int R,int val)
{
if (l>=L && r<=R) {
lazy[rt]=val+1;
tree[rt]=qpow(val+1,r-l+1);
return;
}
int mid=(l+r)>>1;
if (lazy[rt]!=-1) push_down(l,r,rt);
if (mid>=L) update(lson,L,R,val);
if (mid<R) update(rson,L,R,val);
tree[rt]=tree[lc]*tree[rc]%mod;
}
ll query(int l,int r,int rt,int L,int R)
{
ll ans=1;
if (l>=L && r<=R) {return tree[rt];}
int mid=(l+r)>>1;
if (lazy[rt]!=-1) push_down(l,r,rt);
if (mid>=L) ans=ans*query(lson,L,R)%mod;
if (mid<R) ans=ans*query(rson,L,R)%mod;
return ans;
}
int main(int argc, char const *argv[])
{
int n,m;
scanf ("%d%d",&n,&m);
build(1,n,1);
while (m--){
int opt,l,r,v,pos;
scanf ("%d",&opt);
if (opt==1){
scanf ("%d%d%d",&l,&r,&v);
update(1,n,1,l,r,v);
}
else if (opt==2){
scanf ("%d%d",&pos,&v);
update(1,n,1,pos,pos,v);
}
else {
scanf ("%d%d",&l,&r);
printf("%lld
",query(1,n,1,l,r));
}
}
return 0;
}