【题意】
N个节点的树,每个点权值 vi ,求树上是否存在一条路径,使得路径上权值乘积模 106+3 为 K ,若存在,输出路径两端点,若有多解,输出字典序最小解。
【分析】
很好的一道题。
求树上点对的问题,容易想到点分治,但是点分治后判断两个点乘积取模后为
接下来就是点分治中一点小技巧的处理了。。只有
106
,开数组就行了不需要
map
。
【代码】
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#define N 100005
#define M 1000005
#define mod 1000003
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
typedef pair<int,int> pa;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,K,cnt,root,ans1,ans2,sum;
int b[N<<1],p[N],nextedge[N<<1];
int a[N],f[N],sz[N],deep[N],d[N],inv[M],mp[M],id[M];
bool Flag[N];
int Qpow(int x,int y)
{
int rtn=1;
while(y){
if(y&1) rtn=(ll)rtn*x%mod;
x=(ll)x*x%mod;y>>=1;
}
return rtn;
}
void Get_Inv()
{
for(int i=1;i<mod;i++)
inv[i]=Qpow(i,mod-2);
}
void Add(int x,int y)
{
cnt++;
b[cnt]=y;
nextedge[cnt]=p[x];
p[x]=cnt;
}
void Anode(int x,int y){
Add(x,y);Add(y,x);
}
void Input_Init()
{
cnt=0;ans1=ans2=INF;
for(int i=1;i<=n;i++) a[i]=read(),p[i]=Flag[i]=0;
for(int i=1;i<n;i++)
{
static int x,y;
x=read(),y=read();
Anode(x,y);
}
sum=n;f[0]=INF;
}
void Get_Root(int x,int fa)
{
sz[x]=1;f[x]=0;
for(int i=p[x];i;i=nextedge[i])
{
int v=b[i];
if(v==fa||Flag[v]) continue;
Get_Root(v,x);
sz[x]+=sz[v];
f[x]=max(f[x],sz[v]);
}
f[x]=max(f[x],sum-sz[x]);
root=f[root]>f[x]?x:root;
}
void Get_Deep(int x,int fa)
{
deep[++deep[0]]=d[x];id[deep[0]]=x;
for(int i=p[x];i;i=nextedge[i])
{
int v=b[i];if(v==fa||Flag[v]) continue;
d[v]=(ll)d[x]*a[v]%mod;
Get_Deep(v,x);
}
}
void Update(int x,int y)
{
x=(ll)inv[x]*K%mod;
int tmp=mp[x];
if(!tmp) return;
if(tmp<y) swap(tmp,y);
if(y<ans1||y==ans1&&tmp<ans2) ans1=y,ans2=tmp;
}
void Pre(int x,int fa,int now)
{
deep[0]=0;d[x]=now;
Get_Deep(x,fa);
}
void Dfs(int x)
{
Flag[x]=1;mp[a[x]]=x;
for(int i=p[x];i;i=nextedge[i])
{
int v=b[i];if(Flag[v]) continue;
Pre(v,x,a[v]);
for(int j=1;j<=deep[0];j++) Update(deep[j],id[j]);
Pre(v,x,(ll)a[x]*a[v]%mod);
for(int j=1;j<=deep[0];j++)
{
int tmp=mp[deep[j]];
if(!tmp||tmp>id[j]) mp[deep[j]]=id[j];
}
}
mp[a[x]]=0;
for(int i=p[x];i;i=nextedge[i])
{
int v=b[i];if(Flag[v]) continue;
Pre(v,x,(ll)a[x]*a[v]%mod);
for(int j=1;j<=deep[0];j++) mp[deep[j]]=0;
}
for(int i=p[x];i;i=nextedge[i])
{
int v=b[i];if(Flag[v]) continue;
sum=sz[v];root=0;
Get_Root(v,0);
Dfs(root);
}
}
void Solve()
{
if(ans1==INF) printf("No solution\n");
else printf("%d %d\n",ans1,ans2);
}
int main()
{
Get_Inv();
while(scanf("%d%d",&n,&K)!=EOF)
{
Input_Init();
Get_Root(1,0);
Dfs(root);
Solve();
}
return 0;
}