Skip to content

Commit 4d72dba

Browse files
authored
Merge branch 'algorithmzuo:main' into main
2 parents 63c0ef6 + 888a640 commit 4d72dba

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3858
-296
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.

src/class118/Code01_KthAncestor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public static void dfs(int i, int f) {
6868
deep[i] = deep[f] + 1;
6969
}
7070
stjump[i][0] = f;
71-
for (int p = 1; (1 << p) <= deep[i]; p++) {
71+
for (int p = 1; p <= power; p++) {
7272
stjump[i][p] = stjump[stjump[i][p - 1]][p - 1];
7373
}
7474
for (int e = head[i]; e != 0; e = next[e]) {

src/class118/Code02_Multiply1.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public static void addEdge(int u, int v) {
6464
public static void dfs(int u, int f) {
6565
deep[u] = deep[f] + 1;
6666
stjump[u][0] = f;
67-
for (int p = 1; (1 << p) <= deep[u]; p++) {
67+
for (int p = 1; p <= power; p++) {
6868
stjump[u][p] = stjump[stjump[u][p - 1]][p - 1];
6969
}
7070
for (int e = head[u]; e != 0; e = next[e]) {

src/class118/Code02_Multiply2.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,16 @@ public static void dfs(int root) {
7979
// u : 当前处理的点
8080
// f : 当前点u的父节点
8181
// e : 处理到几号边了
82-
// 如果e==-1,表示之前没有处理过u的任何边
83-
// 如果e==0,表示u的边都已经处理完了
82+
// 如果e==-1,表示之前没有处理过u的任何边
83+
// 如果e==0,表示u的边都已经处理完了
8484
push(root, 0, -1);
8585
while (stackSize > 0) {
8686
pop();
8787
if (e == -1) {
8888
deep[u] = deep[f] + 1;
8989
stjump[u][0] = f;
90-
for (int s = 1; (1 << s) <= deep[u]; s++) {
91-
stjump[u][s] = stjump[stjump[u][s - 1]][s - 1];
90+
for (int p = 1; p <= power; p++) {
91+
stjump[u][p] = stjump[stjump[u][p - 1]][p - 1];
9292
}
9393
e = head[u];
9494
} else {

src/class119/Code01_EmergencyAssembly1.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ public class Code01_EmergencyAssembly1 {
4040

4141
public static int cnt;
4242

43+
// deep[i] : i节点在第几层,算距离用
4344
public static int[] deep = new int[MAXN];
4445

46+
// 利用stjump求最低公共祖先
4547
public static int[][] stjump = new int[MAXN][LIMIT];
4648

4749
public static int togather;
@@ -71,7 +73,7 @@ public static void addEdge(int u, int v) {
7173
public static void dfs(int u, int f) {
7274
deep[u] = deep[f] + 1;
7375
stjump[u][0] = f;
74-
for (int p = 1; (1 << p) <= deep[u]; p++) {
76+
for (int p = 1; p <= power; p++) {
7577
stjump[u][p] = stjump[stjump[u][p - 1]][p - 1];
7678
}
7779
for (int e = head[u]; e != 0; e = next[e]) {

src/class119/Code01_EmergencyAssembly2.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
//void dfs(int u, int f) {
5656
// deep[u] = deep[f] + 1;
5757
// stjump[u][0] = f;
58-
// for (int p = 1; (1 << p) <= deep[u]; p++) {
58+
// for (int p = 1; p <= power; p++) {
5959
// stjump[u][p] = stjump[stjump[u][p - 1]][p - 1];
6060
// }
6161
// for (int e = head[u]; e != 0; e = edgeNext[e]) {

src/class119/Code02_Trucking.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ public class Code02_Trucking {
3838
// 并查集
3939
public static int[] father = new int[MAXN];
4040

41-
public static int cnt;
41+
// 给的树有可能是森林,所以需要判断节点是否访问过了
42+
public static boolean[] visited = new boolean[MAXN];
4243

44+
// 最大生成树建图
4345
public static int[] head = new int[MAXN];
4446

4547
public static int[] next = new int[MAXM << 1];
@@ -48,14 +50,15 @@ public class Code02_Trucking {
4850

4951
public static int[] weight = new int[MAXM << 1];
5052

53+
public static int cnt;
54+
5155
public static int[] deep = new int[MAXN];
5256

57+
// stjump[u][p] : u节点往上跳2的次方步,到达什么节点
5358
public static int[][] stjump = new int[MAXN][LIMIT];
5459

55-
public static int[][] stweight = new int[MAXN][LIMIT];
56-
57-
// 给的树有可能是森林,所以需要判断节点是否访问过了
58-
public static boolean[] visited = new boolean[MAXN];
60+
// stmin[u][p] : u节点往上跳2的次方步的路径中,最小的权值
61+
public static int[][] stmin = new int[MAXN][LIMIT];
5962

6063
public static int log2(int n) {
6164
int ans = 0;
@@ -71,8 +74,8 @@ public static void build(int n) {
7174
for (int i = 1; i <= n; i++) {
7275
father[i] = i;
7376
}
74-
Arrays.fill(head, 1, n + 1, 0);
7577
Arrays.fill(visited, 1, n + 1, false);
78+
Arrays.fill(head, 1, n + 1, 0);
7679
}
7780

7881
public static void kruskal(int n, int m) {
@@ -109,15 +112,15 @@ public static void dfs(int u, int w, int f) {
109112
if (f == 0) {
110113
deep[u] = 1;
111114
stjump[u][0] = u;
112-
stweight[u][0] = Integer.MAX_VALUE;
115+
stmin[u][0] = Integer.MAX_VALUE;
113116
} else {
114117
deep[u] = deep[f] + 1;
115118
stjump[u][0] = f;
116-
stweight[u][0] = w;
119+
stmin[u][0] = w;
117120
}
118-
for (int p = 1; (1 << p) <= deep[u]; p++) {
121+
for (int p = 1; p <= power; p++) {
119122
stjump[u][p] = stjump[stjump[u][p - 1]][p - 1];
120-
stweight[u][p] = Math.min(stweight[u][p - 1], stweight[stjump[u][p - 1]][p - 1]);
123+
stmin[u][p] = Math.min(stmin[u][p - 1], stmin[stjump[u][p - 1]][p - 1]);
121124
}
122125
for (int e = head[u]; e != 0; e = next[e]) {
123126
if (!visited[to[e]]) {
@@ -138,7 +141,7 @@ public static int lca(int a, int b) {
138141
int ans = Integer.MAX_VALUE;
139142
for (int p = power; p >= 0; p--) {
140143
if (deep[stjump[a][p]] >= deep[b]) {
141-
ans = Math.min(ans, stweight[a][p]);
144+
ans = Math.min(ans, stmin[a][p]);
142145
a = stjump[a][p];
143146
}
144147
}
@@ -147,12 +150,12 @@ public static int lca(int a, int b) {
147150
}
148151
for (int p = power; p >= 0; p--) {
149152
if (stjump[a][p] != stjump[b][p]) {
150-
ans = Math.min(ans, Math.min(stweight[a][p], stweight[b][p]));
153+
ans = Math.min(ans, Math.min(stmin[a][p], stmin[b][p]));
151154
a = stjump[a][p];
152155
b = stjump[b][p];
153156
}
154157
}
155-
ans = Math.min(ans, Math.min(stweight[a][0], stweight[b][0]));
158+
ans = Math.min(ans, Math.min(stmin[a][0], stmin[b][0]));
156159
return ans;
157160
}
158161

src/class119/Code03_QueryPathMinimumChangesToSame.java

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class Code03_QueryPathMinimumChangesToSame {
1919

2020
public static int MAXW = 26;
2121

22+
// 链式前向星建图
2223
public static int[] headEdge = new int[MAXN];
2324

2425
public static int[] edgeNext = new int[MAXN << 1];
@@ -29,6 +30,10 @@ public class Code03_QueryPathMinimumChangesToSame {
2930

3031
public static int tcnt;
3132

33+
// weightCnt[i][w] : 从头节点到i的路径中,权值为w的边有几条
34+
public static int[][] weightCnt = new int[MAXN][MAXW + 1];
35+
36+
// 以下所有的结构都是为了tarjan算法做准备
3237
public static int[] headQuery = new int[MAXN];
3338

3439
public static int[] queryNext = new int[MAXM << 1];
@@ -39,35 +44,38 @@ public class Code03_QueryPathMinimumChangesToSame {
3944

4045
public static int qcnt;
4146

42-
public static int[][] stcnt = new int[MAXN][MAXW + 1];
43-
4447
public static boolean[] visited = new boolean[MAXN];
4548

4649
public static int[] father = new int[MAXN];
4750

4851
public static int[] lca = new int[MAXM];
4952

50-
public int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {
53+
public static int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {
5154
build(n);
5255
for (int[] edge : edges) {
5356
addEdge(edge[0], edge[1], edge[2]);
5457
addEdge(edge[1], edge[0], edge[2]);
5558
}
59+
// 从头节点到每个节点的边权值词频统计
60+
dfs(0, 0, -1);
5661
int m = queries.length;
5762
for (int i = 0; i < m; i++) {
5863
addQuery(queries[i][0], queries[i][1], i);
5964
addQuery(queries[i][1], queries[i][0], i);
6065
}
61-
tarjan(0, 0, -1);
66+
// 得到每个查询的最低公共祖先
67+
tarjan(0, -1);
6268
int[] ans = new int[m];
63-
for (int i = 0; i < m; i++) {
64-
int allCnt = 0, maxCnt = 0, pathCnt;
65-
for (int j = 1; j <= MAXW; j++) {
66-
// 特别重要的结论
67-
// 很多题可以用到
68-
pathCnt = stcnt[queries[i][0]][j] + stcnt[queries[i][1]][j] - 2 * stcnt[lca[i]][j];
69-
maxCnt = Math.max(maxCnt, pathCnt);
70-
allCnt += pathCnt;
69+
for (int i = 0, a, b, c; i < m; i++) {
70+
a = queries[i][0];
71+
b = queries[i][1];
72+
c = lca[i];
73+
int allCnt = 0; // 从a到b的路,所有权值的边一共多少条
74+
int maxCnt = 0; // 从a到b的路,权值重复最多的次数
75+
for (int w = 1, wcnt; w <= MAXW; w++) { // 所有权值枚举一遍
76+
wcnt = weightCnt[a][w] + weightCnt[b][w] - 2 * weightCnt[c][w];
77+
maxCnt = Math.max(maxCnt, wcnt);
78+
allCnt += wcnt;
7179
}
7280
ans[i] = allCnt - maxCnt;
7381
}
@@ -91,33 +99,38 @@ public static void addEdge(int u, int v, int w) {
9199
headEdge[u] = tcnt++;
92100
}
93101

102+
// 当前来到u节点,父亲节点f,从f到u权重为w
103+
// 统计从头节点到u节点,每种权值的边有多少条
104+
// 信息存放在weightCnt[u][1..26]里
105+
public static void dfs(int u, int w, int f) {
106+
if (u == 0) {
107+
Arrays.fill(weightCnt[u], 0);
108+
} else {
109+
for (int i = 1; i <= MAXW; i++) {
110+
weightCnt[u][i] = weightCnt[f][i];
111+
}
112+
weightCnt[u][w]++;
113+
}
114+
for (int e = headEdge[u]; e != 0; e = edgeNext[e]) {
115+
if (edgeTo[e] != f) {
116+
dfs(edgeTo[e], edgeValue[e], u);
117+
}
118+
}
119+
}
120+
94121
public static void addQuery(int u, int v, int i) {
95122
queryNext[qcnt] = headQuery[u];
96123
queryTo[qcnt] = v;
97124
queryIndex[qcnt] = i;
98125
headQuery[u] = qcnt++;
99126
}
100127

101-
public static int find(int i) {
102-
if (i != father[i]) {
103-
father[i] = find(father[i]);
104-
}
105-
return father[i];
106-
}
107-
108-
public void tarjan(int u, int w, int f) {
128+
// tarjan算法批量查询两点的最低公共祖先
129+
public static void tarjan(int u, int f) {
109130
visited[u] = true;
110-
if (u == 0) {
111-
Arrays.fill(stcnt[u], 0);
112-
} else {
113-
for (int i = 1; i <= MAXW; i++) {
114-
stcnt[u][i] = stcnt[f][i];
115-
}
116-
stcnt[u][w]++;
117-
}
118131
for (int e = headEdge[u]; e != 0; e = edgeNext[e]) {
119132
if (edgeTo[e] != f) {
120-
tarjan(edgeTo[e], edgeValue[e], u);
133+
tarjan(edgeTo[e], u);
121134
}
122135
}
123136
for (int e = headQuery[u], v; e != 0; e = queryNext[e]) {
@@ -129,4 +142,11 @@ public void tarjan(int u, int w, int f) {
129142
father[u] = f;
130143
}
131144

145+
public static int find(int i) {
146+
if (i != father[i]) {
147+
father[i] = find(father[i]);
148+
}
149+
return father[i];
150+
}
151+
132152
}

0 commit comments

Comments
 (0)