题意:
3种询问。
1 l r v,代表[l,r]区间每个数乘以v
2 l r v,代表[l,r]区间每个数变成v次方
3 l r,求[l,r]区间乘积
思路:
裸的线段树维护区间次幂和区间乘积。lazy1表示子区间还需要乘以lazy1,lazy2表示子区间要变成lazy2次方。
注意维护次幂的时候要模(mod-1)(欧拉降幂),且要先维护lazy2,再维护lazy1。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
const int mod = 1e9 + 7;
struct Tree {
int l,r;
ll mul; //总的乘积
ll lazy1; //乘积
ll lazy2; //次幂
}t[maxn << 2];
int a[maxn];
ll qpow(ll x,ll n) {
ll res = 1;
n %= (mod - 1);
while(n) {
if(n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
void pushup(int i) {
t[i].mul = t[i * 2].mul * t[i * 2 + 1].mul % mod;
}
void pushdown(int i) {
if(t[i].lazy2 != 1) {
t[i * 2].mul = qpow(t[i * 2].mul,t[i].lazy2);
t[i * 2 + 1].mul = qpow(t[i * 2 + 1].mul,t[i].lazy2);
t[i * 2].lazy2 = t[i * 2].lazy2 * t[i].lazy2 % (mod - 1);
t[i * 2 + 1].lazy2 = t[i * 2 + 1].lazy2 * t[i].lazy2 % (mod - 1);
t[i * 2].lazy1 = qpow(t[i * 2].lazy1 ,t[i].lazy2);
t[i * 2 + 1].lazy1 = qpow(t[i * 2 + 1].lazy1,t[i].lazy2);
t[i].lazy2 = 1;
}
if(t[i].lazy1 != 1) {
t[i * 2].mul = t[i * 2].mul * qpow(t[i].lazy1,t[i * 2].r - t[i * 2].l + 1) % mod;
t[i * 2 + 1].mul = t[i * 2 + 1].mul * qpow(t[i].lazy1,t[i * 2 + 1].r - t[i * 2 + 1].l + 1) % mod;
t[i * 2].lazy1 = t[i * 2].lazy1 * t[i].lazy1 % mod;
t[i * 2 + 1].lazy1 = t[i * 2 + 1].lazy1 * t[i].lazy1 % mod;
t[i].lazy1 = 1;
}
}
void build(int i,int l,int r) {
t[i].l = l;
t[i].r = r;
t[i].lazy1 = 1;
t[i].lazy2 = 1;
if(l == r) {
t[i].mul = a[l];
return;
}
int m = (l + r) >> 1;
build(i * 2,l,m);
build(i * 2 + 1,m + 1,r);
pushup(i);
}
ll query(int i,int x,int y) {
if(x <= t[i].l && t[i].r <= y) {
return t[i].mul;
}
int m = (t[i].l + t[i].r) >> 1;
pushdown(i);
ll res = 1;
if(x <= m) res = res * query(i * 2,x,y) % mod;
if(y > m) res = res * query(i * 2 + 1,x,y) % mod;
pushup(i);
return res;
}
void update1(int i,int x,int y,ll v) {
//乘积
if(x <= t[i].l && t[i].r <= y) {
t[i].mul = t[i].mul * qpow(v,t[i].r - t[i].l + 1) % mod;
t[i].lazy1 = t[i].lazy1 * v % mod;
return;
}
pushdown(i);
int m = (t[i].l + t[i].r) >> 1;
if(x <= m) update1(i * 2,x,y,v);
if(y > m) update1(i * 2 + 1,x,y,v);
pushup(i);
}
void update2(int i,int x,int y,ll v) {
//次幂
if(x <= t[i].l && t[i].r <= y) {
t[i].mul = qpow(t[i].mul,v);
t[i].lazy1 = qpow(t[i].lazy1,v);
t[i].lazy2 = t[i].lazy2 * v % (mod - 1);
return;
}
int m = (t[i].l + t[i].r) >> 1;
pushdown(i);
if(x <= m) update2(i * 2,x,y,v);
if(y > m) update2(i * 2 + 1,x,y,v);
pushup(i);
}
int main() {
int T;scanf("%d",&T);
while(T--) {
int n,q;scanf("%d%d",&n,&q);
for(int i = 1;i <= n;i++) {
scanf("%lld",&a[i]);
}
build(1,1,n);
for(int i = 1;i <= q;i++) {
int op;scanf("%d",&op);
if(op == 1) {
int l,r,v;scanf("%d%d%d",&l,&r,&v);
update1(1,l,r,v);
} else if(op == 2) {
int l,r,v;scanf("%d%d%d",&l,&r,&v);
update2(1,l,r,v);
} else {
int l,r;scanf("%d%d",&l,&r);
printf("%lld\n",query(1,l,r));
}
}
}
return 0;
}