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
", get_LL(ans), get_divitor_num(ans));
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Alruddy/p/7707725.html