题目大意:一棵 n 个结点的树,每个结点有一个权值,问你是否存在两个点对它们路径上的点值的乘积 mod ( 1 0 6 + 3 ) (10^6 + 3) (106+3) = k,如果有,输出字典序最小的方案。否则输出No solution
题解:由于时间卡得比较紧,用O(n)递推预处理逆元。因为 1 0 6 + 3 10^6 + 3 106+3 是素数,如果已知 a a a,根据 ( a ∗ b ) m o d    1 0 6 + 3 = k (a * b) \mod 10^6 + 3 = k (a∗b)mod106+3=k,可以用 a 的逆元乘k算出 b。当前分治结点为 u,dis[v] 为 v 到 u 的路径点权乘积,用map 存一下dis 对应的点 v,暴力合并更新答案。
(可能是我用了vector的原因,加上测试样例是多组,常数非常大)
复杂度
O
(
n
∗
l
o
g
n
∗
l
o
g
n
)
O(n * logn * logn)
O(n∗logn∗logn)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
#define fir first
#define sec second
const int inf = 0x3f3f3f3f;
int n,k;
const int maxn = 1e6 + 500;
const int p = 1e6 + 3;
vector<int> g[maxn];
pii ans;
int mul(int a,int b) {
return (int)((1ll * a * b) % p);
}
bool cmp(pii a,pii b) {
return a.fir == b.fir ? a.sec < b.sec : a.fir < b.fir;
}
map<int,int> pot;
vector<int> t,ft;
int a[maxn],root,sz[maxn],tot,f[maxn],inv[maxn * 10];
int dis[maxn];
bool done[maxn];
void initInv() {
inv[0] = inv[1] = 1;
for (int i = 2; i < p; i++) {
inv[i] = 1ll * (p - p / i) * inv[p % i] % p;
}
}
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
void getroot(int u,int fa) {
f[u] = 0;sz[u] = 1;
for(auto it : g[u]) {
if(it == fa || done[it]) continue;
getroot(it,u);
sz[u] += sz[it];
f[u] = max(f[u],sz[it]);
}
f[u] = max(f[u],tot - sz[u]);
if(f[u] < f[root] || !root) root = u;
}
void dfs(int u,int fa) {
int d = dis[u];
t.push_back(u);
for(auto it : g[u]) {
if(it == fa || done[it]) continue;
dis[it] = mul(dis[u],a[it]);
dfs(it,u);
}
}
void solve(int u) {
done[u] = true;
pot.clear();pot[a[u]] = u;
for(auto it : g[u]) {
if(done[it]) continue;
t.clear();
dis[it] = mul(a[it],a[u]);
dfs(it,u);
for(auto i : t) {
int x = mul(dis[i],inv[a[u]]);
int p = mul(inv[x],k);
if(pot[p]) {
int u = pot[p],v = i;
if(u > v) swap(u,v);
if(ans.fir > u || (ans.fir == u && ans.sec > v)) ans = pii(u,v);
}
}
for(auto i : t)
if(!pot[dis[i]] || pot[dis[i]] > i) pot[dis[i]] = i;
}
}
void divide(int u) {
solve(u);
for(auto it : g[u]) {
if(done[it]) continue;
tot = sz[it];root = 0;
getroot(it,-1);divide(root);
}
}
int main() {
initInv();
while(scanf("%d%d",&n,&k) != EOF) {
for(int i = 1; i <= n; i++) {
a[i] = read();
g[i].clear();done[i] = false;
}
for(int i = 1; i < n; i++) {
int u,v;
u = read();v = read();
g[u].push_back(v);
g[v].push_back(u);
}
ans = pii(inf,inf);
root = 0;tot = n;getroot(1,-1);
divide(root);
if(ans.fir != inf && ans.sec != inf)
printf("%d %d\n",ans.fir,ans.sec);
else puts("No solution");
}
return 0;
}