区间加法,区间乘法,单点查询。
洛谷线段树2
屡清加法乘法的关系,定义答案为 a*mut+add
对于整块:
新的乘w,mut和add都要乘w
新的加w,add加w
//Stay foolish,stay hungry,stay young,stay simple
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cctype>
using namespace std;
inline int read_d(){
int ret=0,f=1;char c;
while(c=getchar(),!isdigit(c)) f=c=='-'?-1:1;
while(isdigit(c)){
ret=ret*10+c-'0';
c=getchar();
}
return ret*f;
}
const int MAXN=500005;
const int MOD=10007;
int n;
int num,block;
int a[MAXN],l[MAXN],r[MAXN],bl[MAXN];
int add[MAXN],mut[MAXN];
void pushdown(int id){
for(int i=l[id];i<=r[id];i++){
a[i]=(a[i]*mut[id]+add[id]) % MOD;
}
mut[id]=1;
add[id]=0;
}
void build(){
block=sqrt(n);
num=n/block;
if(n%block) num++;
for(int i=1;i<=num;i++){
l[i]=(i-1)*block+1;
r[i]=i*block;
mut[i]=1;
}
for(int i=1;i<=n;i++){
bl[i]=(i-1)/block+1;
}
r[num]=n;
}
int query(int x){
return (((a[x]*mut[bl[x]])%MOD)+add[bl[x]])%MOD;
}
void updata_mut(int x,int y,int w){
if(bl[x]==bl[y]){
pushdown(bl[x]);
for(int i=x;i<=y;i++){
a[i]*=w;
a[i]%=MOD;
}
return ;
}
pushdown(bl[x]);
for(int i=x;i<=r[bl[x]];i++){
a[i]*=w;a[i]%=MOD;
}
pushdown(bl[y]);
for(int i=l[bl[y]];i<=y;i++){
a[i]*=w;a[i]%=MOD;
}
for(int i=bl[x]+1;i<=bl[y]-1;i++){
mut[i]*=w;mut[i]%=MOD;
add[i]*=w;add[i]%=MOD;
}
}
void updata_add(int x,int y,int w){
if(bl[x]==bl[y]){
pushdown(bl[x]);
for(int i=x;i<=y;i++){
a[i]+=w;
}
return ;
}
pushdown(bl[x]);
for(int i=x;i<=r[bl[x]];i++){
a[i]+=w;a[i]%=MOD;
}
pushdown(bl[y]);
for(int i=l[bl[y]];i<=y;i++){
a[i]+=w;a[i]%=MOD;
}
for(int i=bl[x]+1;i<=bl[y]-1;i++){
add[i]+=w;add[i]%=MOD;
}
}
int main(){
n=read_d();
for(int i=1;i<=n;i++){
a[i]=read_d();
}
build();
for(int i=1;i<=n;i++){
int q=read_d(),x=read_d(),y=read_d(),w=read_d();
if(q==0) updata_add(x,y,w);
if(q==1) updata_mut(x,y,w);
if(q==2) printf("%d
",query(y));
}
return 0;
}