题目大意:
给你一颗树,树上节点有个权值
a
i
a_i
ai,现在问你这颗树上是否存在一条路径这个路径上面权值的乘积模1e6+3等于k。
如果有多组答案输出字典序最小的答案
解题思路:
1.首先我们知道
a
×
b
%
m
o
d
=
k
a\times b\%mod=k
a×b%mod=k
a
=
(
k
×
i
n
v
[
b
]
)
a=(k\times inv[b])
a=(k×inv[b])
2.知道这个公式后我们就可以直接点分治了
为了字典序最小,我们要把每次模数对应的最小的结点存下面,但是不能每次都暴力初始化,用到那个数值才初始化哪个。
3.点分每次更新子树大小的时候
now_node = siz[it] > siz[u] ? now_node - siz[it] : siz[u];
会TLE!!!!!
代码:
#pragma comment(linker,"/STACK:102400000,102400000")
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
const int mod = 1e6 + 3;
vector<int> G[maxn];
int N, K, val[maxn];
//..................
int root, Mx, now_node;
int max_son[maxn], siz[maxn];
bool vis[maxn];
ll qmi(ll a, ll b) {
ll res = 1;
while(b) {
if(b & 1) res = (a * res) % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void getroot(int u, int fa) {
siz[u] = 1;
max_son[u] = 0;
for(int i = 0; i < G[u].size(); ++ i) {
int it = G[u][i];
if(vis[it] || fa == it) continue;
getroot(it,u);
max_son[u] = max(max_son[u],siz[it]);
siz[u] = siz[it] + siz[u];
}
max_son[u] = max(max_son[u],now_node - siz[u]);
if(max_son[u] < Mx) Mx = max_son[u], root = u;
}
pair<int,int> ans;
pair<int,ll> tmp[maxn];
int mul[mod+10], idx;//存对于同一个模数的最小序号
ll lis[maxn], lis_idx;
void dfs(int u, int fa, ll sum) {
int t = (1ll*K*qmi(sum,mod-2))%mod;
if(mul[t] != 1e9) {
if(ans > (pair<int,int>){min(mul[t],u),max(mul[t],u)})
ans = {min(mul[t],u),max(mul[t],u)};
}
tmp[idx++] = {u,sum};
for(int i = 0; i < G[u].size(); ++ i) {
int it = G[u][i];
if(it == fa || vis[it]) continue;
dfs(it, u, sum*val[it]%mod);
}
}
inline void getans(int u) {
for(int i = 0;i < lis_idx; ++ i) mul[lis[i]] = 1e9;
lis_idx = 0;
mul[val[u]] = u;
lis[lis_idx++] = val[u];
for(int i = 0; i < G[u].size(); ++ i) {
int it = G[u][i];
if(vis[it]) continue;
dfs(it, u, val[it] % mod);
for(int i = 0; i < idx; ++ i) {
int t = 1ll * tmp[i].second * val[u] % mod;
mul[t] = min(mul[t],tmp[i].first);
lis[lis_idx++] = t;
}
idx = 0;
}
}
void Div(int u) {
vis[u] = 1;
getans(u);
for(int i = 0; i < G[u].size(); ++ i) {
int it = G[u][i];
if(vis[it]) continue;
Mx = 1e9, root = 0;
now_node = siz[it];
getroot(it,0);
Div(root);
}
}
int main() {
for(int i = 0; i < mod; ++ i) mul[i] = 1e9;
while(scanf("%d%d",&N,&K) != EOF) {
ans = {1e9,1e9};
for(int i = 1; i <= N; ++ i) vis[i] = 0, G[i].clear();
for(int i = 1; i <= N; ++ i)
scanf("%d",&val[i]);
for(int i = 1; i < N; ++ i) {
int l, r;
scanf("%d%d",&l,&r);
G[l].push_back(r);
G[r].push_back(l);
}
if(K == 0) {
printf("No solution\n");
continue;
}
now_node = N;
Mx = 1e9, root = 0;
getroot(1,0);
Div(root);
if(ans.second == 1e9) printf("No solution\n");
else printf("%d %d\n",ans.first,ans.second);
}
return 0;
}