Gym 101466K 树状数组+时间戳

题目链接


题意:
有一颗根为0的树,每个顶点都有一个权值,有两种操作。

  • SEED u x 节点u的权值乘上x
  • RAND u 输出以节点u为根的子树的节点权值的乘积

思路:
每个权值很大,乘积会超出整数范围,考虑使用,质数指数表示法,分解质因数。
乘积就是各个质因数指数的加和。
使用dfs访问一边树,对于某个子树来说,dfs访问的时间戳是连续的,起点是子树的根。要求得乘积也就是去求某个连续的区间的和,可以使用树状数组来解决。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
const int mod = 1e9 + 7;
struct Value
{
    LL prime[8];
    Value(){memset(prime, 0, sizeof(prime));}
};
vector<int> G[N];
int fa[N];
int prime[] = {2,3,5,7,11,13}, prime_cnt = 6;
int start[N], over[N], dfs_clock;

LL quick_exp(LL a, LL n){
    LL ans = 1;
    while(n){
        if(n&1) ans = (ans*a)%mod;
        n >>= 1;
        a = (a*a)%mod;
    }
    return ans;
}
Value multip(Value a, Value b){
    Value ans;
    for(int i = 0; i < prime_cnt; i++)
        ans.prime[i] = a.prime[i] + b.prime[i];
    return ans;
}

Value get_value(LL x){
    Value val;
    for(int i = 0; i < prime_cnt; i++){
        if(x % prime[i] == 0){
            while(x % prime[i] == 0){
                val.prime[i]++;
                x /= prime[i];
            }
        }
    }
    return val;
}

LL get_LL(Value a){
    LL ans = 1;
    for(int i = 0; i < prime_cnt; i++)
    {
        ans = ans*quick_exp(prime[i], a.prime[i]);
        ans %= mod;
    }
    return ans;
}

LL get_divitor_num(Value x){
    LL ans = 1;
    for(int i = 0; i < prime_cnt; i++)
        ans = (ans*(x.prime[i]+1))%mod;
    return ans;
}

Value val[N];
Value p[N];
int n, u, v;

void init(){
    memset(fa, -1, sizeof(fa));
    for(int i = 0; i < N; i++){
        G[i].clear();
        start[i] = over[i] = 0;
    }
    dfs_clock = 0;
}

void dfs(int u){
    start[u] = ++dfs_clock;
    for(int i = 0; i < (int)G[u].size(); i++){
        int v = G[u][i];
        dfs(v);
    }
    over[u] = dfs_clock;
}

inline int lowbit(int i){
    return i&(-i);
}
void add(int x, Value v){
    for(int i = x; i < N; i += lowbit(i) ){
        for(int j = 0; j < prime_cnt; j++){
            p[i].prime[j] += v.prime[j];
        }
    }
}
Value sum(int x){
    Value ans;
    for(int i = x; i ; i -= lowbit(i)){
        for(int j = 0; j < prime_cnt; j++){
            ans.prime[j] += p[i].prime[j];
        }
    }
    return ans;
}
Value query(int l, int r){
    Value ans;
    Value R = sum(r);
    Value L = sum(l-1);
    for(int i = 0; i < prime_cnt; i++){
        ans.prime[i] = R.prime[i] - L.prime[i];
    }
    return ans;
}

int main()
{
    // freopen("in.txt", "r", stdin);
    init();
    scanf("%d", &n);
    for(int i = 0; i < n-1; i++){
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        fa[v] = u;
    }
    for(int i = 0; i < n; i++){
        LL tmp;
        scanf("%lld", &tmp);
        val[i] = get_value(tmp);
    }
    dfs(0);
    for(int i = 0; i < n; i++)
    {
        // cout << start[i] << " " << over[i] << endl;
        add(start[i], val[i]);
    }


    int q,a;
    LL x;
    char cmd[10];
    scanf("%d", &q);
    while(q--){
        scanf("%s", cmd);
        if(cmd[0] == 'S'){
            scanf("%d%lld", &a, &x);
            Value extra = get_value(x);
            add(start[a], extra);
        }
        else if(cmd[0] == 'R'){
            scanf("%d", &a);
            int L = start[a], R = over[a];
            // cout << L << " " << R << endl;
            Value ans = query(L, R);
            printf("%lld %lld\n", get_LL(ans), get_divitor_num(ans));
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Alruddy/p/7707725.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值