E - Yet Another Data Structure Problem ZOJ - 3998(线段树维护区间乘积,k次方)

题意:
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;
}

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/109072162