题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4812
题目描述:给一棵n个节点的树,每一个节点有一个权值Vi(vi<10^6+3),问是否存在一条路径a到b(a<b),使得权值的乘积mod(10^6+3)=k
解题思路:解题思路比较容易想到,就是树分治。对于每一个选定的重心,维护以该中心为根的子树中的节点到根的乘积,因为乘积mod(10^6+3)之后最多只有10^6+3种可能,所以直接开一个数组存一存就行了。但是我一直TLE,其实是由于我每次都处理一遍逆元,所以超时了,只要处理一次逆元就可以了
//#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#include<time.h>
#define ll long long
#define db double
#define PB push_back
using namespace std;
const int N = 100005;
const ll MOD = 1000003;
const int M = 2*N;
const int K = 1000005;
const int INF = 1000000000;
int head[N],to[M],next[M];
int nedge;
ll val[N];//,inv[K];
ll niyuan[K];
int ans[2];
void init()
{
memset(head,-1,sizeof(head));
nedge=0;
}
void add(int a,int b)
{
to[nedge]=b,next[nedge]=head[a],head[a]=nedge++;
}
ll quick_pow(ll t,int k)
{
ll res=1LL;
while(k>0)
{
if(k&1) res=(res*t)%MOD;;
k>>=1;
t=(t*t)%MOD;
}
return res;
}
void get_niyuan()
{
for(ll i=1;i<MOD;i++)
niyuan[i]=quick_pow(i,(int)(MOD-2));
}
int min_val,root; //min_val=INF;
int tol[N],min_node[N]; //min_node=0;
bool vis[N];
void get_root(int k,int fa,int &n)
{
min_node[k]=0,tol[k]=1;
for(int i=head[k];i>=0;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
get_root(to[i],k,n);
tol[k]+=tol[to[i]];
min_node[k]=max(min_node[k],tol[to[i]]);
}
}
min_node[k]=max(min_node[k],n-tol[k]);
if(min_node[k]<min_val)
{
min_val=min_node[k];
root=k;
}
}
ll g[K];
int f[K],ch[K],mk[K],cnt;
void get_g(int k,int fa,ll v)
{
g[cnt]=v,ch[cnt++]=k;
for(int i=head[k];i>=0;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
get_g(to[i],k,(v*val[to[i]])%MOD);
}
}
}
void update(int a,int b)
{
if(a>b) swap(a,b);
if(a<ans[0]) ans[0]=a,ans[1]=b;
else if(a==ans[0]&&b<ans[1]) ans[1]=b;
}
ll big_k;
void work(int k,int fa,int n)
{
min_val=INF;
get_root(k,fa,n);
int rt=root;
vis[rt]=true;
for(int i=head[rt];i>=0;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
if(tol[to[i]]>tol[rt]) work(to[i],rt,n-tol[rt]);
else work(to[i],rt,tol[to[i]]);
}
}
for(int i=head[rt];i>=0;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
cnt=0;
get_g(to[i],rt,val[to[i]]);
for(int j=0;j<cnt;j++)
{
ll t=(g[j]*val[rt])%MOD;
// if(t==big_k) update(rt,ch[j]);
t=(niyuan[t]*big_k)%MOD;
// t=inv[t];
if(mk[t]==rt)
update(f[t],ch[j]);
}
for(int j=0;j<cnt;j++)
{
if(mk[g[j]]!=rt)
{
mk[g[j]]=rt;
f[g[j]]=ch[j];
}else
{
f[g[j]]=min(f[g[j]],ch[j]);
}
}
}
}
vis[rt]=false;
}
int main()
{
#ifdef PKWV
freopen("in.in","r",stdin);
#endif // PKWV
clock_t st,ed;
st=clock();
int n;
get_niyuan();
while(scanf("%d%I64d",&n,&big_k)+1)
{
for(int i=1;i<=n;i++) scanf("%I64d",&val[i]);
init();
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
ans[0]=ans[1]=MOD;
memset(mk,-1,sizeof(mk));
work(1,-1,n);
if(ans[0]==MOD) printf("No solution\n");
else printf("%d %d\n",ans[0],ans[1]);
}
ed=clock();
// printf("use time: %f\n",(db)(ed-st)/CLOCKS_PER_SEC);
return 0;
}