树上的点分治。
首先为了避免超时预处理逆元,对于x(<mod),我们希望找到f-1(x) = y 满足y * x % mod = k。
由存在a, b : x *a + y * b = gcd(x, y), mod 为素数,故有 x * a + mod * b = 1。
由EXTENDED-EUCLID找出a (< mod)。
对于树上的分治,首先找出当前树的重心,处理剔除重心后的各个子树,合法链属于其中一个子树或者经过树根。
acm.hdu.edu.cn/showproblem.php?pid=4812
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #pragma comment(linker,"/STACK:102400000,102400000") 5 6 using namespace std; 7 typedef __int64 LL; 8 const int inf = 0x3f3f3f3f; 9 const int maxn = 1e5 + 10; 10 const int mod = 1e6 + 3; 11 12 struct Edge{ 13 int to, next; 14 }edge[maxn * 2]; 15 int head[maxn], f[mod], belong[mod], g[mod]; 16 bool vis[maxn]; 17 int n, N, root; 18 LL K, val[maxn], path[maxn]; 19 int cnt1, mini; 20 LL d, x, y; 21 int ans[2], sum[maxn], id[maxn]; 22 23 void addEdge(int u, int v){ 24 edge[N].next = head[u]; 25 edge[N].to = v; 26 head[u] = N++; 27 } 28 29 void eEuclid(LL a, LL b){ 30 if(!b){ 31 d = a; x = 1; y = 0; 32 return; 33 } 34 eEuclid(b, a % b); 35 LL x1 = x; 36 x = y; 37 y = x1 - a / b * y; 38 } 39 40 void init(){ 41 //calculate inverse element 42 for(int i = 0; i < mod; i++){ 43 eEuclid(mod, i); 44 while(y < 0) y += mod; 45 g[i] = y % mod; 46 } 47 } 48 49 void getRoot(int u){ 50 sum[u] = 1; 51 int maxii = 0; 52 vis[u] = 1; 53 for(int i = head[u]; i + 1; i = edge[i].next){ 54 int v = edge[i].to; 55 if(vis[v]) continue; 56 getRoot(v); 57 sum[u] += sum[v]; 58 maxii = max(sum[v], maxii); 59 } 60 vis[u] = 0; 61 maxii = max(maxii, sum[0] - sum[u]); 62 if(maxii < mini) mini = maxii, root = u; 63 } 64 65 void update(int a, int b){ 66 if(a > b) swap(a, b); 67 if(ans[0] == -1 || ans[0] > a){ 68 ans[0] = a, ans[1] = b; 69 return; 70 } 71 if(ans[0] == a && ans[1] > b) ans[1] = b; 72 } 73 74 void dfs(int u, LL num){ 75 path[cnt1] = num * val[u] % mod; 76 id[cnt1++] = u; 77 LL tem = path[cnt1 - 1]; 78 vis[u] = 1; 79 for(int i = head[u]; i + 1; i = edge[i].next){ 80 int v = edge[i].to; 81 if(vis[v]) continue; 82 dfs(v, tem); 83 } 84 vis[u] = 0; 85 } 86 87 void solve(int u, int cnt){ 88 if(cnt == 1) return; 89 sum[0] = cnt; 90 mini = inf; 91 getRoot(u); 92 vis[root] = 1; 93 for(int i = head[root]; i + 1; i = edge[i].next){ 94 int v = edge[i].to; 95 if(vis[v]) continue; 96 cnt1 = 0; 97 dfs(v, 1); 98 for(int j = 0; j < cnt1; j++){ 99 if(path[j] * val[root] % mod == K) update(id[j], root); 100 LL tem = K * g[path[j] * val[root] % mod] % mod; 101 if(belong[tem] != N) continue; 102 update(id[j], f[tem]); 103 } 104 for(int j = 0; j < cnt1; j++){ 105 int tem = path[j]; 106 if(belong[tem] != N || f[tem] > id[j]) f[tem] = id[j], belong[tem] = N; 107 } 108 } 109 N++; 110 for(int i = head[root]; i + 1; i = edge[i].next){ 111 int v = edge[i].to; 112 if(vis[v]) continue; 113 solve(v, sum[v]); 114 } 115 } 116 117 int main(){ 118 init(); 119 while(~scanf("%d%I64d", &n, &K)){ 120 for(int i = 1; i <= n; i++) scanf("%I64d", &val[i]); 121 memset(head, -1, sizeof head); 122 memset(belong, -1, sizeof belong); 123 memset(ans, -1, sizeof ans); 124 memset(vis, 0, sizeof vis); 125 N = 0; 126 for(int i = 1, p, q; i < n; i++){ 127 scanf("%d%d", &p, &q); 128 addEdge(p, q); 129 addEdge(q, p); 130 } 131 N = 0; 132 solve(1, n); 133 if(ans[0] == -1) puts("No solution"); 134 else printf("%d %d ", ans[0], ans[1]); 135 } 136 return 0; 137 }