传送门:【HDU】4812 D Tree
题目分析:点分治搞之。乘积等于K的路径。
首先我们定义一个path[ i ]用以记录从根结点x在子树x内的第 i 条路径的值(乘积)。然后每次我们搞完当前重心rt的一棵子树以后,我们用判断K*逆元[ path[ i ] * val[ rt ] %MOD ] % MOD 是否存在来确定乘积为K的路径是否存在,然后再用这个path[ i ]去更新best[ path[ i ] ](best[ i ]为取值为 i 的路径的端点最小标号 )。
求逆元可以用p^(mod - 2 ) % mod来,毕竟互素随便搞?
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #pragma comment(linker,"/STACK:102400000,102400000") #define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next ) #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) const int MAXN = 100005 ; const int MAXE = 200005 ; const int MOD = 1000003 ; const int INF = 0x3f3f3f3f ; struct Edge { int v ; Edge* next ; } E[MAXE] , *H[MAXN] , *edge ; struct Node { int c , idx ; Node () {} Node ( int idx , int c ) : idx ( idx ) , c ( c ) {} } path[MAXN] ; int flag[MOD] ; int ni[MOD] ; int best[MOD] ; bool vis[MAXN] ; int val[MAXN] ; int siz[MAXN] ; int num[MAXN] ; int node_num ; int ans[2] ; int n , K ; int root ; int cnt ;//path int dep ;//flag void clear () { dep = 0 ; edge = E ; num[0] = n ; clr ( H , 0 ) ; clr ( vis , 0 ) ; clr ( flag , 0 ) ; ans[0] = ans[1] = INF ; } void addedge ( int u , int v ) { edge -> v = v ; edge -> next = H[u] ; H[u] = edge ++ ; } int pow ( int a , int b ) { LL res = 1 , tmp = a ; while ( b ) { if ( b & 1 ) res = res * tmp % MOD ; tmp = tmp * tmp % MOD ; b >>= 1 ; } return res ; } void get_siz ( int u , int fa = 0 ) { siz[u] = 1 ; travel ( e , H , u ) { int v = e -> v ; if ( !vis[v] && v != fa ) { get_siz ( v , u ) ; siz[u] += siz[v] ; } } } void get_root ( int u , int fa = 0 ) { num[u] = 0 ; travel ( e , H , u ) { int v = e -> v ; if ( !vis[v] && v != fa ) { get_root ( v , u ) ; num[u] = max ( num[u] , siz[v] ) ; } } num[u] = max ( num[u] , node_num - siz[u] ) ; if ( num[u] < num[root] ) root = u ; } void get_path ( int u , int c , int fa = 0 ) { path[cnt ++] = Node ( u , c ) ; travel ( e , H , u ) { int v = e -> v ; if ( !vis[v] && v != fa ) { get_path ( v , ( LL ) c * val[v] % MOD , u ) ; } } } void update_ans ( int u , int v ) { if ( u > v ) swap ( u , v ) ; if ( u < ans[0] || u == ans[0] && v < ans[1] ) ans[0] = u , ans[1] = v ; } void dfs ( int u ) { get_siz ( u ) ; node_num = siz[u] ; root = 0 ; get_root ( u ) ; int rt = root ; vis[rt] = 1 ; travel ( e , H , rt ) { int v = e -> v ; if ( !vis[v] ) dfs ( v ) ; } ++ dep ; travel ( e , H , rt ) { int v = e -> v ; if ( vis[v] ) continue ; cnt = 0 ; get_path ( v , val[v] % MOD ) ; rep ( i , 0 , cnt ) { int tmp = ( LL ) val[rt] * path[i].c % MOD ; if ( tmp == K ) update_ans ( rt , path[i].idx ) ; int x = ( LL ) K * ni[tmp] % MOD ; if ( flag[x] == dep ) update_ans ( best[x] , path[i].idx ) ; } rep ( i , 0 , cnt ) { int c = path[i].c , idx = path[i].idx ; if ( flag[c] != dep || best[c] > idx ) { best[c] = idx ; flag[c] = dep ; } } } vis[rt] = 0 ; } void solve () { int x , y , c ; clear () ; FOR ( i , 1 , n ) scanf ( "%d" , &val[i] ) ; rep ( i , 1 , n ) { scanf ( "%d%d" , &x , &y ) ; addedge ( x , y ) ; addedge ( y , x ) ; } dfs ( 1 ) ; if ( ans[0] != INF ) printf ( "%d %d\n" , ans[0] , ans[1] ) ; else printf ( "No solution\n" ) ; } int main () { rep ( i , 0 , MOD ) ni[i] = pow ( i , MOD - 2 ) ; while ( ~scanf ( "%d%d" , &n , &K ) ) solve () ; return 0 ; }