标签:可以转化 blank mod style 数组 val dde div 代码
[题目链接]
https://codeforces.com/contest/986/problem/E
[算法]
X到Y的路径积 , 可以转化为X到根的路径积乘Y到根的路径积 , 除以LCA到根的路径积 , 再除以LCA父节点到根的路径积
考虑如何计算根到X路径上每个点与Value的GCD之积
不妨对于每个质数P开一个数组cnt[] , 表示根到当前节点P^i有多少个 , 我们可以在DFS的过程中维护这个数组
将询问离线即可
时间复杂度 : O(V + NlogN + QlogV^2)
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXLOG 30 const int P = 1e9 + 7; const int MAXN = 1e5 + 10; const int MAXP = 1e6 + 10; const int MAXV = 1e7 + 10; struct edge { int to , nxt; } e[MAXN << 1]; struct info { int value , home; bool type; } ; int tot , n , t; int a[MAXN],depth[MAXN],prime[MAXP],head[MAXN],ans[MAXN],f[MAXV]; int cnt[MAXP][MAXLOG],anc[MAXN][MAXLOG]; vector< info > q[MAXN]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - ‘0‘; x *= f; } inline void addedge(int u,int v) { t++; e[t] = (edge){v,head[u]}; head[u] = t; } inline int exp_mod(int a,int n) { int res = 1 , b = a; while (n > 0) { if (n & 1) res = 1ll * res * b % P; b = 1ll * b * b % P; n >>= 1; } return res; } inline int inv(int x) { return exp_mod(x,P - 2); } inline void dfs(int u,int fa) { depth[u] = depth[fa] + 1; for (int i = 1; i < MAXLOG; i++) { if (depth[u] <= (1 << i)) break; anc[u][i] = anc[anc[u][i - 1]][i - 1]; } for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa) continue; anc[v][0] = u; depth[v] = depth[u] + 1; dfs(v,u); } } inline int lca(int u,int v) { if (depth[u] > depth[v]) swap(u,v); for (int i = MAXLOG - 1; i >= 0; i--) { if (depth[anc[v][i]] >= depth[u]) v = anc[v][i]; } if (u == v) return u; for (int i = MAXLOG - 1; i >= 0; i--) { if (anc[u][i] != anc[v][i]) u = anc[u][i] , v = anc[v][i]; } return anc[u][0]; } inline void modify(int x,int delta) { for (int i = 1; 1ll * prime[i] * prime[i] <= x; i++) { if (x % prime[i] == 0) { int p = 0; while (x % prime[i] == 0) { x /= prime[i]; p++; } cnt[i][p] += delta; } } if (x != 1) { int pos = lower_bound(prime + 1,prime + tot + 1,x) - prime; cnt[pos][1] += delta; } } inline int query(int x) { int ret = 1; for (int i = 1; 1ll * prime[i] * prime[i] <= x; i++) { if (x % prime[i] == 0) { int p = 0; while (x % prime[i] == 0) { p++; x /= prime[i]; } int s = 0; for (int j = 1; j <= p; j++) s += cnt[i][j] * j; for (int j = p + 1; j < MAXLOG; j++) s += cnt[i][j] * p; ret = 1ll * ret * exp_mod(prime[i],s) % P; } } if (x != 1) { int pos = lower_bound(prime + 1,prime + tot + 1,x) - prime; int s = 0; for (int i = 1; i < MAXLOG; i++) s += cnt[pos][i]; ret = 1ll * ret * exp_mod(x,s) % P; } return ret; } inline void solve(int u,int fa) { modify(a[u],1); for (unsigned i = 0; i < q[u].size(); i++) { if (q[u][i].type) ans[q[u][i].home] = 1ll * ans[q[u][i].home] * query(q[u][i].value) % P; else ans[q[u][i].home] = 1ll * ans[q[u][i].home] * inv(query(q[u][i].value)) % P; } for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa) continue; solve(v,u); } modify(a[u],-1); } int main() { read(n); for (int i = 2; i < MAXV; i++) { if (!f[i]) { f[i] = i; prime[++tot] = i; } for (int j = 1; j <= tot; j++) { int tmp = i * prime[j]; if (tmp >= MAXV) break; f[tmp] = prime[j]; if (prime[j] == f[i]) break; } } for (int i = 1; i < n; i++) { int u , v; read(u); read(v); addedge(u,v); addedge(v,u); } dfs(1,0); for (int i = 1; i <= n; i++) read(a[i]); int Q; read(Q); for (int i = 1; i <= Q; i++) { int u , v , x; read(u); read(v); read(x); int Lca = lca(u,v); q[u].push_back((info){x,i,true}); q[v].push_back((info){x,i,true}); q[Lca].push_back((info){x,i,false}); if (Lca != 1) q[anc[Lca][0]].push_back((info){x,i,false}); ans[i] = 1; } solve(1,0); for (int i = 1; i <= Q; i++) printf("%d\n",ans[i]); return 0; }
[Codeforces 986E] Prince's Problem
标签:可以转化 blank mod style 数组 val dde div 代码
原文地址:https://www.cnblogs.com/evenbao/p/9739488.html