题意:
有一颗根为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
", get_LL(ans), get_divitor_num(ans));
}
}
return 0;
}