1
+ import java .util .ArrayList ;
2
+ import java .util .Arrays ;
3
+ import java .util .List ;
4
+
5
+ public class Solution3559 {
6
+ static final int MOD = (int ) (1e9 + 7 );
7
+
8
+ // 快速幂 res = a^b % mod
9
+ private long quickPow (long a , long b ) {
10
+ long res = 1L ;
11
+ while (b > 0 ) {
12
+ if ((b & 1 ) != 0 ) res = res * a % MOD ;
13
+ a = a * a % MOD ;
14
+ b >>= 1 ;
15
+ }
16
+ return res ;
17
+ }
18
+
19
+ private List <Integer >[] g ;
20
+ private int dfn ;
21
+ private int [][] nodes ; // l, r
22
+ private final int mx = 17 ;
23
+ private int [][] pa ;
24
+ private int [] dep ;
25
+
26
+ public int [] assignEdgeWeights (int [][] edges , int [][] queries ) {
27
+ int n = edges .length + 1 ;
28
+ g = new ArrayList [n + 1 ];
29
+ Arrays .setAll (g , e -> new ArrayList <>());
30
+ for (int [] e : edges ) {
31
+ int x = e [0 ] - 1 , y = e [1 ] - 1 ;
32
+ g [x ].add (y );
33
+ g [y ].add (x );
34
+ }
35
+ dfn = 0 ;
36
+ nodes = new int [n ][2 ];
37
+ pa = new int [n ][mx ];
38
+ dep = new int [n ];
39
+ build (0 , -1 );
40
+ for (int i = 0 ; i + 1 < mx ; i ++) {
41
+ for (int v = 0 ; v < pa .length ; v ++) {
42
+ int p = pa [v ][i ];
43
+ if (p != -1 ) {
44
+ pa [v ][i + 1 ] = pa [p ][i ];
45
+ } else {
46
+ pa [v ][i + 1 ] = -1 ;
47
+ }
48
+ }
49
+ }
50
+
51
+ int q = queries .length ;
52
+ int [] ans = new int [q ];
53
+ for (int i = 0 ; i < q ; i ++) {
54
+ int k = get_path_sum (queries [i ][0 ] - 1 , queries [i ][1 ] - 1 );
55
+ if (k == 0 ) continue ;
56
+ ans [i ] = (int ) quickPow (2 , k - 1 );
57
+ }
58
+ return ans ;
59
+ }
60
+
61
+ int get_path_sum (int u , int v ) {
62
+ int ancestor = getLCA (u , v );
63
+ return dep [u ] + dep [v ] - 2 * dep [ancestor ];
64
+ }
65
+
66
+ int build (int v , int fa ) {
67
+ dfn ++;
68
+ nodes [v ][0 ] = dfn ;
69
+ pa [v ][0 ] = fa ;
70
+ int sz = 1 ;
71
+ for (int w : g [v ]) {
72
+ if (w != fa ) {
73
+ dep [w ] = dep [v ] + 1 ;
74
+ sz += build (w , v );
75
+ }
76
+ }
77
+ nodes [v ][1 ] = nodes [v ][0 ] + sz - 1 ;
78
+ return sz ;
79
+ }
80
+
81
+ int uptoDep (int v , int d ) {
82
+ for (int k = dep [v ] - d ; k > 0 ; k &= k - 1 ) {
83
+ v = pa [v ][Integer .numberOfTrailingZeros (k )];
84
+ }
85
+ return v ;
86
+ }
87
+
88
+ int getLCA (int v , int w ) {
89
+ if (dep [v ] > dep [w ]) {
90
+ int tmp = v ;
91
+ v = w ;
92
+ w = tmp ;
93
+ }
94
+ w = uptoDep (w , dep [v ]);
95
+ if (w == v ) return v ;
96
+ for (int i = mx - 1 ; i >= 0 ; i --) {
97
+ if (pa [v ][i ] != pa [w ][i ]) {
98
+ v = pa [v ][i ];
99
+ w = pa [w ][i ];
100
+ }
101
+ }
102
+ return pa [v ][0 ];
103
+ }
104
+ }
105
+ /*
106
+ 3559. 给边赋权值的方案数 II
107
+ https://leetcode.cn/problems/number-of-ways-to-assign-edge-weights-ii/description/
108
+
109
+ 第 157 场双周赛 T4。
110
+
111
+ 给你一棵有 n 个节点的无向树,节点从 1 到 n 编号,树以节点 1 为根。树由一个长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示在节点 ui 和 vi 之间有一条边。
112
+ 一开始,所有边的权重为 0。你可以将每条边的权重设为 1 或 2。
113
+ 两个节点 u 和 v 之间路径的 代价 是连接它们路径上所有边的权重之和。
114
+ 给定一个二维整数数组 queries。对于每个 queries[i] = [ui, vi],计算从节点 ui 到 vi 的路径中,使得路径代价为 奇数 的权重分配方式数量。
115
+ 返回一个数组 answer,其中 answer[i] 表示第 i 个查询的合法赋值方式数量。
116
+ 由于答案可能很大,请对每个 answer[i] 取模 10^9 + 7。
117
+ 注意: 对于每个查询,仅考虑 ui 到 vi 路径上的边,忽略其他边。
118
+ 提示:
119
+ 2 <= n <= 10^5
120
+ edges.length == n - 1
121
+ edges[i] == [ui, vi]
122
+ 1 <= queries.length <= 10^5
123
+ queries[i] == [ui, vi]
124
+ 1 <= ui, vi <= n
125
+ edges 表示一棵合法的树。
126
+
127
+ 最近公共祖先 LCA。
128
+ 答案为 2^{k-1} % mod。k 为两点之间的距离(边数),套 LCA 模板即可。
129
+ 相似题目: 3553. 包含给定路径的最小带权子树 II
130
+ https://leetcode.cn/problems/minimum-weighted-subgraph-with-the-required-paths-ii/description/
131
+ rating 2509 (clist.by)
132
+ */
0 commit comments