题意:给你一颗树,树上的每个顶点有一个权值,给定一个数k,让你找一条路径,使得这条路径上的点的权值的乘积模上一个数后等于k.
解题思路:这是一道树分治的经典题目,也是我做的第一道树分治的题目,这题的话比较简单,几乎模板,需要注意的地方是逆元要一次求出,还要注意一下hash的地方,写的太丑会t.
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 10;
const LL mod = 1e6 + 3;
int N, K;
int E;
bool flag;
int Size, Maxn;
LL inv[maxn];//逆元
int head[maxn];
LL value[maxn];
int Hash[maxn];
bool visit[maxn];
pair<int, int> ans;
int dp[maxn];//以i为根的子树的节点数
int root;
vector<pair<int, LL> > temp;
struct edge{
int v, Nxt;
}Edge[maxn<<1];
void add_edge(int u, int v)
{
Edge[E].v = v;
Edge[E].Nxt = head[u];
head[u] = E++;
}
void init()
{
memset(head, -1, sizeof(head));
memset(visit, false, sizeof(visit));
memset(Hash, -1, sizeof(Hash));
flag = false;
temp.clear();
root = -1;
E = 0;
}
LL quick_mod(LL x, LL i)
{
LL ans = 1;
ans %= mod;
while(i)
{
if(i&1) ans = (ans * x) % mod;
i >>= 1;
x = (x * x) % mod;
}
return ans;
}
void getInv()
{
for(int i = 1; i <= (int)mod; i++)
{
inv[i] = quick_mod((LL)i, mod - 2);
}
}
void getRoot(int u, int fa)//找出树的重心
{
dp[u] = 1;
int Max = 0;
for(int i = head[u]; i != -1; i = Edge[i].Nxt)
{
int v = Edge[i].v;
if(v == fa) continue;
if(!visit[v])
{
getRoot(v, u);
dp[u] += dp[v];
Max = max(Max, dp[v]);
}
}
Max = max(Max, Size - dp[u]);
if(Max < Maxn)
{
Maxn = Max;
root = u;
}
}
void getDis(int u, int fa, LL x)
{
LL res = x * value[u] % mod;
temp.push_back(make_pair(u, res));
for(int i = head[u]; i != -1; i = Edge[i].Nxt)
{
int v = Edge[i].v;
if(v == fa) continue;
if(!visit[v])
{
getDis(v, u, res);
}
}
}
void update(int u, int v)
{
if(u > v) swap(u, v);
if(!flag)
{
flag = true;
ans = make_pair(u, v);
}
else
{
if(u < ans.first) ans = make_pair(u, v);
else if(u == ans.first && v < ans.second) ans = make_pair(u, v);
}
}
LL d[maxn];
void work(int u)
{
visit[u] = true;
int cnt = 0;
for(int i = head[u]; i != -1; i = Edge[i].Nxt)
{
int v = Edge[i].v;
if(visit[v]) continue;
temp.clear();
getDis(v, v, value[u]);
for(int j = 0; j < temp.size(); j++)
{
int id = temp[j].first;
LL x = temp[j].second;
if(x == K) update(id, u);
LL judge = (inv[x] % mod * K) % mod;
if(Hash[judge] == -1) continue;
else
{
update(id, Hash[judge]);
}
}
for(int j = 0; j < temp.size(); j++)
{
int id = temp[j].first;
LL x = temp[j].second;
x = (x * inv[value[u]]) % mod;
d[++cnt] = x;
if(Hash[x] == -1) Hash[x] = id;
else
{
Hash[x] = min(Hash[x], id);
}
}
}
for(int i = 1; i <= cnt; i++) Hash[d[i]] = -1;
for(int i = head[u]; i != -1; i = Edge[i].Nxt)
{
int v = Edge[i].v;
if(visit[v]) continue;
Maxn = dp[v];
Size = dp[v];
root = -1;
getRoot(v, v);
work(root);
}
}
int main()
{
getInv();
while(~scanf("%d%d", &N, &K))
{
init();
for(int i = 1; i <= N; i++)
{
scanf("%lld", &value[i]);
}
int u, v;
for(int i = 1; i < N; i++)
{
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
Maxn = N;
Size = N;
getRoot(1, 1);
work(root);
if(flag) printf("%d %d\n", ans.first, ans.second);
else printf("No solution\n");
}
return 0;
}