codeforces - 1114F Please, another Queries on Array?

版权声明: https://blog.csdn.net/moon_sky1999/article/details/87351751

题目来源:http://codeforces.com/contest/1114/problem/F

题意:

给定一个序列c,给定两种操作

(1)对区间[l,r]中所有元素*x。

(2)查询区间[l,r]中所有元素成积的欧拉函数值。

数组c的所有元素均<300,每次乘操作的x也均<300。

可以预先得知,300以内的素数共有62个,可以预先保存到数组中。

求取区间内所有数的欧拉函数值,可以将区间所有数的乘积转成p1^q1*p2^q2*...*pn^qn,其中p1~pn均是素数,这样欧拉函数值就是 总乘积*(p1-1)/p1*(p2-1)/p2*...*(pn-1)/pn。

除法操作可以转为乘1e9+7意义下的逆元,可以预先处理得到。

现在即须知道区间内出现了多少种素数。

由于素数最多仅有62种,可以用状压的方法,压为一个long long的数,表示该区间素数存在情况。

这样,线段树维护两个量:区间总乘积sum和区间素数出现情况pos,以及相应的lazy标记。(代码中add对饮sum的,lz对应pos的)

线段树维护区间内所有数均*一个数的操作与+类似,维护pos也即维护区间或(or)的值。

代码:

#include <bits/stdc++.h>

#define ll long long
using namespace std;

const ll mod = 1e9 + 7;
const int maxn = 4e5 + 10;
int a[maxn], n, q;
ll pri[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
            107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
            227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293};
ll ni[65];//保存逆元

ll pow_mod(ll a, ll b, ll m) {
    ll ans = 1;
    while (b) {
        if (b & 1)ans = ans * a % m;
        a = a * a % m;
        b >>= 1;
    }
    return ans;
}

struct tree {
    int left, right;
    ll sum, add;
    ll pos, lz;
} c[maxn << 2];

void build(int id, int l, int r) {
    c[id].left = l;
    c[id].right = r;
    c[id].add = 1;
    c[id].lz = 0;
    if (l == r) {
        c[id].sum = a[l];
        for (ll i = 0; i < 62; ++i) {
            if (a[l] % pri[i] == 0) {
                c[id].pos = (c[id].pos | (1ll << i));
                a[l] /= pri[i];
                while (a[l] % pri[i] == 0)a[l] /= pri[i];
            }
            if (a[l] < pri[i])break;
        }
        return;
    }
    int mid = (l + r) >> 1;
    build(id << 1, l, mid);
    build(id << 1 | 1, mid + 1, r);
    c[id].pos = ((c[id << 1].pos) | (c[id << 1 | 1].pos));
    c[id].sum = (c[id << 1].sum * c[id << 1 | 1].sum) % mod;
}

void pushdown(int id) {
    c[id << 1].sum =
            (c[id << 1].sum * pow_mod(c[id].add, (c[id << 1].right - c[id << 1].left + 1), mod)) % mod;
    c[id << 1 | 1].sum =
            (c[id << 1 | 1].sum * pow_mod(c[id].add, (c[id << 1 | 1].right - c[id << 1 | 1].left + 1), mod)) % mod;
    c[id << 1].add = c[id << 1].add * c[id].add % mod;
    c[id << 1 | 1].add = c[id << 1 | 1].add * c[id].add % mod;
    c[id].add = 1;
    c[id << 1].pos = (c[id << 1].pos | c[id].lz);
    c[id << 1 | 1].pos = (c[id << 1 | 1].pos | c[id].lz);
    c[id << 1].lz = (c[id << 1].lz | c[id].lz);
    c[id << 1 | 1].lz = (c[id << 1 | 1].lz | c[id].lz);
    c[id].lz = 0;
}

void update(int id, int l, int r, ll v, ll p) {
    if (c[id].left > r || c[id].right < l)return;
    if (c[id].left >= l && c[id].right <= r) {
        c[id].sum = (pow_mod(v, (c[id].right - c[id].left + 1), mod) * c[id].sum) % mod;
        c[id].add = (c[id].add * v) % mod;
        c[id].pos = (c[id].pos | p);
        c[id].lz = (p | c[id].lz);
        return;
    }
    if (c[id].add > 1)pushdown(id);
    if (c[id].lz)pushdown(id);
    update(id << 1, l, r, v, p);
    update(id << 1 | 1, l, r, v, p);
    c[id].sum = c[id << 1].sum * c[id << 1 | 1].sum % mod;
    c[id].pos = (c[id << 1].pos | c[id << 1 | 1].pos);
}

ll query_sum(int id, int l, int r) {
    if (r < c[id].left || l > c[id].right)return 1;
    if (c[id].left >= l && c[id].right <= r) {
        return c[id].sum;
    }
    if (c[id].add>1)pushdown(id);
    ll ans = query_sum(id << 1, l, r) * query_sum(id << 1 | 1, l, r) % mod;
    c[id].sum = c[id << 1].sum * c[id << 1 | 1].sum % mod;
    return ans;
}

ll query_pos(int id, int l, int r) {
    if (r < c[id].left || l > c[id].right)return 0;
    if (c[id].left >= l && c[id].right <= r) {
        return c[id].pos;
    }
    if (c[id].lz)pushdown(id);
    ll pos = (query_pos(id << 1, l, r) | query_pos(id << 1 | 1, l, r));
    c[id].pos = (c[id << 1].pos | c[id << 1 | 1].pos);
    return pos;
}

char s[10];

int main() {
    for (int i = 0; i < 62; ++i) {
        ni[i] = pow_mod(pri[i], mod - 2, mod);
    }
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    build(1, 1, n);
    int l, r, x;
    ll ans, p;
    while (q--) {
        scanf("%s", s);
        if (s[0] == 'T') {
            scanf("%d%d", &l, &r);
            ans = query_sum(1, l, r);
            p = query_pos(1, l, r);
            for (ll i = 0; i < 62; ++i) {
                if ((p & (1ll << i)) != 0) {
                    ans = ans * ni[i] % mod;
                    ans = ans * (pri[i] - 1) % mod;
                }
            }
            printf("%lld\n", ans);
        } else {
            scanf("%d%d%d", &l, &r, &x);
            ll p = 0;
            ll v = x;
            for (ll i = 0; i < 62; ++i) {
                if (v % pri[i] == 0) {
                    p = (p | (1ll << i));
                    v /= pri[i];
                    while (v % pri[i] == 0) v /= pri[i];
                }
                if (pri[i] > v)break;
            }
            update(1, l, r, x, p);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/moon_sky1999/article/details/87351751
今日推荐