题意:有一棵树,树中所有结点有一个权值,求出字典序最小的点对,满足这两个点间的简单路径中所有结点的权值积等于k
做法:树分治,所有经过x点满足要求的路径点对去更新ans,枚举x即可。
由于这里所有的权值小于mod,所以不用考虑0的情况,方便许多。
用map乱搞会超时,还是老老实实用数组模拟hash。
#include<map>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<climits>
#include<list>
#include<iomanip>
#include<stack>
#include<set>
using namespace std;
typedef long long ll;
const ll mod=1000003;
ll k;
int tail;
int head[100010];
struct Edge
{
int to,next;
}edge[200010];
int mid,tree_size;
bool vis[100010];
int sb_size[100010],mx_size[100010];
void seek_mid(int fa,int from)
{
sb_size[from]=1;
mx_size[from]=0;
for(int i=head[from];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(!vis[to]&&to!=fa)
{
seek_mid(from,to);
sb_size[from]+=sb_size[to];
mx_size[from]=max(mx_size[from],sb_size[from]);
}
}
mx_size[from]=max(mx_size[from],tree_size-sb_size[from]);
if(mx_size[mid]>mx_size[from])
mid=from;
}
int path_size[2];
int path[2][100010],index[2][mod];
ll w[100010];
void cnt(int fa,int from,ll val)
{
if(index[0][val]==0||index[0][val]>from)
{
if(index[0][val]==0)
path[0][path_size[0]++]=val;
index[0][val]=from;
}
sb_size[from]=1;
for(int i=head[from];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(!vis[to]&&fa!=to)
{
cnt(from,to,val*w[to]%mod);
sb_size[from]+=sb_size[to];
}
}
}
int ansl,ansr;
void update(int l,int r)
{
if(l>r)
swap(l,r);
if(l<ansl)
{
ansl=l;
ansr=r;
}
else if(l==ansl&&r<ansr)
ansr=r;
}
ll fac[mod];
void cnt()
{
for(int i=head[mid];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(!vis[to])
{
path_size[0]=0;
cnt(mid,to,w[to]);
for(int j=0;j<path_size[0];j++)
{
if(path[0][j]*w[mid]%mod==k)
update(mid,index[0][path[0][j]]);
int t=k*fac[path[0][j]*w[mid]%mod]%mod;
if(index[1][t]!=0)
update(index[0][path[0][j]],index[1][t]);
}
for(int j=0;j<path_size[0];j++)
{
if(index[1][path[0][j]]==0||
index[1][path[0][j]]>index[0][path[0][j]])
{
if(index[1][path[0][j]]==0)
path[1][path_size[1]++]=path[0][j];
index[1][path[0][j]]=index[0][path[0][j]];
}
index[0][path[0][j]]=0;
}
}
}
}
void dfs()
{
vis[mid]=1;
path_size[1]=0;
cnt();
for(int i=0;i<path_size[1];i++)
index[1][path[1][i]]=0;
for(int i=head[mid];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(!vis[to])
{
mx_size[mid=0]=100010;
tree_size=sb_size[to];
seek_mid(0,to);
dfs();
}
}
}
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void create()
{
for(int i=1;i<mod;i++)
fac[i]=qpow(i,mod-2);
}
void add(int from,int to)
{
edge[tail].to=to;
edge[tail].next=head[from];
head[from]=tail++;
}
int main()
{
create();
int n;
while(scanf("%d",&n)!=EOF)
{
memset(vis,0,sizeof(vis));
int t;
scanf("%d",&t);
k=t;
for(int i=1;i<=n;i++)
{
scanf("%d",&t);
w[i]=t;
}
tail=0;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
{
int from,to;
scanf("%d%d",&from,&to);
add(from,to);
add(to,from);
}
tree_size=n;
ansl=mx_size[mid=0]=100010;
seek_mid(0,1);
dfs();
if(ansl==100010)
puts("No solution");
else
printf("%d %d\n",ansl,ansr);
}
}