@ZCDHJ
2019-09-24T03:50:13.000000Z
字数 3127
阅读 463
未分类
先将每个询问差分为询问从根到点的路径 之积,然后 dfs 树一遍离线处理。对于 可以看成是对于 的每个质因子的指数取 min,因为 内质数个数不多且指数小,可以开个桶来统计。具体来说,加入一个 时将 的桶里编号从 到 的部分加一,统计 的时候将 的每种质因子及其个数算出来(表示为 ),统计 的桶里 到 的总和即为答案里这种质因子的指数。为了快速地实现质因数分解先用线性筛求出每个数最小的质因子,即可 完成单次分解。
#include <iostream>#include <cstdio>#include <vector>const int MAXN = 1e5;const int MAXV = 1e7;const int MOD = 1e9 + 7;struct Query {int id, x, v;Query() : id(0), x(0), v(0) {}Query(int _id, int _x, int _v) : id(_id), x(_x), v(_v) {}};int n, m, prime_tot, edge, idx;int prime[MAXV | 1], min_prime[MAXV | 1], prime_id[MAXV | 1], fst[MAXN | 1], a[MAXN | 1], ans[MAXN | 1];int dfn[MAXN | 1], topf[MAXN | 1], father[MAXN | 1], size[MAXN | 1], son[MAXN | 1], depth[MAXN | 1];short book[25][664580];bool vis[MAXV | 1];std::vector < Query > queries[MAXN | 1];struct Edge {int to, nxt;Edge() : to(0), nxt(0) {}Edge(int a, int b) : to(b), nxt(fst[a]) {}} e[MAXN << 1 | 1];inline int read( ){register int x = 0;register char ch = getchar();while (!isdigit(ch)) ch = getchar();while (isdigit(ch)) {x = x * 10 + ch - '0';ch = getchar();}return x;}inline void addEdge(int a, int b) {e[++edge] = Edge(a, b);fst[a] = edge;}void dfs1(int x, int y) {father[x] = y;depth[x] = depth[y] + 1;dfn[x] = ++idx;size[x] = 1;for (int k = fst[x]; k; k = e[k].nxt) {int to = e[k].to;if (to == y) continue;dfs1(to, x);size[x] += size[to];if (size[to] > size[son[x]]) son[x] = to;}}void dfs2(int x, int ftop) {topf[x] = ftop;if (!son[x]) return;dfs2(son[x], ftop);for (int k = fst[x]; k; k = e[k].nxt) {int to = e[k].to;if (to == father[x] || to == son[x]) continue;dfs2(to, to);}}int LCA(int x, int y) {while (topf[x] != topf[y]) {if (depth[topf[x]] < depth[topf[y]]) std::swap(x, y);x = father[topf[x]];}return depth[x] < depth[y] ? x : y;}int fast_pow(int x, int y, int mod) {int res = 1, base = x;while (y > 0) {if (y & 1) res = 1LL * res * base % mod;base = 1LL * base * base % mod;y >>= 1;}return res;}void update(int x, int v) {while (x != 1) {int times = 0;int min = min_prime[x];// printf("x=%d min=%d\n", x, min_prime[x]);while (x != 1 && min_prime[x] == min) {++times;x /= min_prime[x];}for (int i = 1; i <= times; ++i) book[i][prime_id[min]] += v;}}int query(int v) {int res = 1;while (v != 1) {int times = 0;int min = min_prime[v];while (v != 1 && min_prime[v] == min) {++times;v /= min_prime[v];}int sum = 0;for (int i = 1; i <= times; ++i) sum += book[i][prime_id[min]];res = 1LL * res * fast_pow(min, sum, MOD) % MOD;}return res;}void calc_dfs(int x) {update(a[x], 1);for (int k = fst[x]; k; k = e[k].nxt) {int to = e[k].to;if (to == father[x]) continue;calc_dfs(to);}for (std::vector < Query > :: iterator it = queries[x].begin(); it != queries[x].end(); ++it) {Query now = *it;int res = query(now.x);if (now.v == 1) ans[now.id] = 1LL * ans[now.id] * res % MOD;else ans[now.id] = 1LL * ans[now.id] * fast_pow(res, MOD - 2, MOD) % MOD;}update(a[x], -1);}int main() {n = read();for (int i = 1; i < n; ++i) {int u = read(), v = read();addEdge(u, v);addEdge(v, u);}for (int i = 1; i <= n; ++i) a[i] = read();for (int i = 2; i <= 1e7; ++i) {if (!vis[i]) {prime[++prime_tot] = i;min_prime[i] = i;prime_id[i] = prime_tot;}for (int j = 1; i * prime[j] <= 1e7 && j <= prime_tot; ++j) {vis[i * prime[j]] = 1;min_prime[i * prime[j]] = prime[j];if (i % prime[j] == 0) break;}}dfs1(1, 0);dfs2(1, 1);m = read();for (int i = 1; i <= m; ++i) {ans[i] = 1;int a = read(), b = read(), x = read();int lca = LCA(a, b);queries[a].push_back(Query(i, x, 1));queries[b].push_back(Query(i, x, 1));queries[lca].push_back(Query(i, x, -1));queries[father[lca]].push_back(Query(i, x, -1));}calc_dfs(1);for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);return 0;}