diff --git "a/ACWing/src/LCA/Tarjan\346\261\202LCA.java" "b/ACWing/src/LCA/Tarjan\346\261\202LCA.java" index 6e1ac98da31025e3636640dc8e1c69682de0ea23..cb117173a8ec3499bdd5412679bf7c2ce4bbbef3 100644 --- "a/ACWing/src/LCA/Tarjan\346\261\202LCA.java" +++ "b/ACWing/src/LCA/Tarjan\346\261\202LCA.java" @@ -54,7 +54,7 @@ public class Tarjan求LCA { } for (int i = 0; i < m; i++) { addq(nextInt(), nextInt(), i); - } + }//存储询问 tarjan(root, 0); for (int i = 0; i < m; i++) { bw.write(result[i] + "\n"); diff --git a/ACWing/src/String/KMP.java b/ACWing/src/String/KMP.java index 4730552538f4b00bdb9ec63371b08ee87a81c134..45d19b19e82e03fac22654f5e2a49f5291e66c07 100644 --- a/ACWing/src/String/KMP.java +++ b/ACWing/src/String/KMP.java @@ -5,6 +5,13 @@ import java.util.Scanner; /** * https://blog.csdn.net/qq_30277239/article/details/100881221 + * 3 + * aba + * 5 + * ababa + * out: + * 0 + * 2 */ public class KMP { public static void main(String[] args) { @@ -46,13 +53,4 @@ public class KMP { } } - static void it() { - ne[0] = -1; - int t = 0; - for (int i = 1; i <= n; i++) { - t = ne[i - 1]; - while (t != -1 && p[i - 1] != p[t]) t = ne[t]; - ne[i] = t + 1; - } - } } diff --git "a/ACWing/src/dp/\345\215\225\350\260\203\351\230\237\345\210\227dp/\347\203\275\347\201\253\344\274\240\351\200\222.java" "b/ACWing/src/dp/\345\215\225\350\260\203\351\230\237\345\210\227dp/\347\203\275\347\201\253\344\274\240\351\200\222.java" index 054b00c9087a3513d12b5058cbf915ca356ee5f9..ce63c2d290cf41870a76a027835d627abdcd1101 100644 --- "a/ACWing/src/dp/\345\215\225\350\260\203\351\230\237\345\210\227dp/\347\203\275\347\201\253\344\274\240\351\200\222.java" +++ "b/ACWing/src/dp/\345\215\225\350\260\203\351\230\237\345\210\227dp/\347\203\275\347\201\253\344\274\240\351\200\222.java" @@ -7,11 +7,42 @@ import java.util.StringTokenizer; import static java.lang.System.in; /** + * 烽火台是重要的军事防御设施,一般建在交通要道或险要处。 + * 一旦有军情发生,则白天用浓烟,晚上有火光传递军情。 + * 在某两个城市之间有 n 座烽火台,每个烽火台发出信号都有一定的代价。 + * 为了使情报准确传递,在连续 m 个烽火台中至少要有一个发出信号。 + * 现在输入 n,m和每个烽火台的代价,请计算在两城市之间准确传递情报所需花费的总代价最少为多少。 + * 输入格式 + * 第一行是两个整数 n,m,具体含义见题目描述; + * 第二行 n 个整数表示每个烽火台的代价 ai。 + * 输出格式 + * 输出仅一个整数,表示最小代价。 + * 数据范围 + * 1≤n,m≤2×10^5, + * 0≤ai≤1000 + * 输入样例: + * 5 3 + * 1 2 5 6 2 + * 输出样例: + * 4 * https://blog.csdn.net/qq_30277239/article/details/104580927 * f[i]表示前1~i且点燃第i个烽火台, * 属性:最小代价 * f[i]找倒数第2个, i-1 i-2...i-m+1 i-m * f[i]=min(f[j] | i-m<=j m时才需要出队头,不需要加等号,这里容易出错。 + * 第二点就是单调队列实现步骤中更新f[i]语句的位置,由于f[i]需要放进队列中, + * 所以需要先计算完f[i]才能够再与队尾元素比较来决定f[i]在队列中的最终位置。具体实现见代码: */ public class 烽火传递 { public static void main(String[] args) throws IOException { diff --git "a/ACWing/src/dp/\345\215\225\350\260\203\351\230\237\345\210\227dp/\347\220\206\346\203\263\347\232\204\346\255\243\346\226\271\345\275\242.java" "b/ACWing/src/dp/\345\215\225\350\260\203\351\230\237\345\210\227dp/\347\220\206\346\203\263\347\232\204\346\255\243\346\226\271\345\275\242.java" index ed8c31b9df2c8129cba5d6209584ab20c231392a..686ed8d277d8d7dbfa38bfc03543240b378ce897 100644 --- "a/ACWing/src/dp/\345\215\225\350\260\203\351\230\237\345\210\227dp/\347\220\206\346\203\263\347\232\204\346\255\243\346\226\271\345\275\242.java" +++ "b/ACWing/src/dp/\345\215\225\350\260\203\351\230\237\345\210\227dp/\347\220\206\346\203\263\347\232\204\346\255\243\346\226\271\345\275\242.java" @@ -28,6 +28,15 @@ import java.util.Scanner; * 输出样例: * 1 * 先预处理求每行的最值,在预处理列 + * 先对矩阵逐行求区间长度是n的滑动窗口的最大最小值,分别存进最大最小值数组。 + * 然后再对求出的最值数组按列再求一次最值, + * 二者之差就是所有n*n正方形区域内的最大整数与最小整数差了。当然,求滑动区间的最值就是使用单调队列实现的。 + * 如图所示,如果要求3*3正方形中的最值, + * 可以先将各行中长度为3的区间的最值存在这个区间开始的格子里,比如上图蓝色的区域, + * 求完后,第一列的前三个格子就存了这个蓝色正方形各行的最值, + * 再竖着对第一行求下长度为3区间的最值存到第一个单元格里,第一个单元格存储的就是整个正方形区域内的最值了。 + * 当然我们是先把初始矩形各行长度为n区间的最值存到一个新的数组,然后再对这个数组竖着求最值存入又一个数组来实现的, + * 以避免值被覆盖。实现细节见代码: */ public class 理想的正方形 { public static void main(String[] args) { @@ -41,14 +50,33 @@ public class 理想的正方形 { } } for (int i = 1; i <= n; i++) { - + getMin(w[i], row_min[i], m); + getMax(w[i], row_max[i], m); + } + int[] a = new int[N]; + int[] b = new int[N]; + int[] c = new int[N]; + int res = (int) 1e9; + for (int i = k; i <= m; i++) { + for (int j = 1; j <= n; j++) { + a[j] = row_min[j][i]; + } + getMin(a, b, n); + for (int j = 1; j <= n; j++) { + a[j] = row_max[j][i]; + } + getMax(a, c, n); + for (int j = k; j <= n; j++) { + res = Math.min(res, c[j] - b[j]); + } } + System.out.println(res); } static void getMin(int[] a, int[] b, int tot) { int hh = 0, tt = -1; for (int i = 1; i <= tot; i++) { - if (hh <= tt && q[hh] <= i - tot) hh++; + if (hh <= tt && q[hh] <= i - k) hh++; while (hh <= tt && a[q[tt]] >= a[i]) tt--; q[++tt] = i; b[i] = a[q[hh]]; @@ -58,7 +86,7 @@ public class 理想的正方形 { static void getMax(int[] a, int[] b, int tot) { int hh = 0, tt = -1; for (int i = 1; i <= tot; i++) { - if (hh <= tt && q[hh] <= i - tot) hh++; + if (hh <= tt && q[hh] <= i - k) hh++; while (hh <= tt && a[q[tt]] <= a[i]) tt--; q[++tt] = i; b[i] = a[q[hh]]; diff --git a/ACWing/src/graph/AcWingEK.java b/ACWing/src/graph/AcWingEK.java new file mode 100644 index 0000000000000000000000000000000000000000..f053ce0e046802252588340fe89dc690d5e7f7e8 --- /dev/null +++ b/ACWing/src/graph/AcWingEK.java @@ -0,0 +1,108 @@ +package graph; + +import java.io.*; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.StringTokenizer; + +import static java.lang.System.in; + +public class AcWingEK { + + public static void main(String[] args) throws IOException { + n = nextInt(); + m = nextInt(); + s = nextInt(); + t = nextInt(); + int a, b, c; + for (int i = 1; i <= m; i++) { + a = nextInt(); + b = nextInt(); + c = nextInt(); + add(a, b, c); + } + System.out.println(ek()); + } + + static int cnt = 1, n, inf = (int) 1e9, t, s, m; + static int[] h = new int[1010]; + static int[] e = new int[20010]; + static int[] ne = new int[20010]; + static int[] w = new int[20010]; + static boolean[] st = new boolean[1202]; + static int[] dis = new int[1202]; + static int[] pre = new int[1010]; + + //加双向边 + static void add(int a, int b, int c) { + e[++cnt] = b; + w[cnt] = c; + ne[cnt] = h[a]; + h[a] = cnt; + e[++cnt] = a; + w[cnt] = 0; + ne[cnt] = h[b]; + h[b] = cnt; + } + + static ArrayDeque q = new ArrayDeque(); + + //使用bfs寻找增广路 + static boolean bfs() { + Arrays.fill(st, false); + q.clear(); + q.push(s); + st[s] = true; + dis[s] = inf; + while (!q.isEmpty()) { + int x = q.pollFirst(); + for (int i = h[x]; i != 0; i = ne[i]) { + int v = e[i]; + if (!st[v] && w[i] != 0) { + dis[v] = Math.min(dis[x], w[i]); + pre[v] = i; + q.push(v); + st[v] = true; + if (v == t) return true; + } + } + } + return false; + } + + static int ek() { + int r = 0; + while (bfs()) { + r += dis[t]; + for (int i = t; i != s; i = e[pre[i] ^ 1]) { + w[pre[i]] -= dis[t]; + w[pre[i] ^ 1] += dis[t]; + } + } + return r; + } + + static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + static BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + static StringTokenizer tokenizer = new StringTokenizer(""); + + static String nextLine() throws IOException {// 读取下一行字符串 + return reader.readLine(); + } + + static String next() throws IOException {// 读取下一个字符串 + while (!tokenizer.hasMoreTokens()) { + //如果没有字符了,就是下一个,使用空格拆分, + tokenizer = new StringTokenizer(reader.readLine()); + } + return tokenizer.nextToken(); + } + + static int nextInt() throws IOException {// 读取下一个int型数值 + return Integer.parseInt(next()); + } + + static double nextDouble() throws IOException {// 读取下一个double型数值 + return Double.parseDouble(next()); + } +} diff --git a/ACWing/src/graph/EK.java b/ACWing/src/graph/EK.java new file mode 100644 index 0000000000000000000000000000000000000000..988586e54917e297d5893891a64d2010f0e52d78 --- /dev/null +++ b/ACWing/src/graph/EK.java @@ -0,0 +1,116 @@ +package graph; + +import java.io.*; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.StringTokenizer; + +import static java.lang.System.in; + +public class EK { + + public static void main(String[] args) throws IOException { + n = nextInt(); + m = nextInt(); + s = nextInt(); + t = nextInt(); + int a, b, c; + for (int i = 1; i <= m; i++) { + a = nextInt(); + b = nextInt(); + c = nextInt(); + if (flag[a][b] == 0) { + add(a, b, c); + flag[a][b] = cnt; + } else { + w[flag[a][b] - 1] += c; + } + } + while (bfs()) { + update(); + } + System.out.println(ans); + } + + static int[][] flag = new int[1001][1001]; + static int cnt = 1, n, inf = Integer.MAX_VALUE / 2, t, s, ans = 0, m; + static int[] h = new int[1010]; + static int[] e = new int[20010]; + static int[] ne = new int[20010]; + static int[] w = new int[20010]; + static boolean[] st = new boolean[1002]; + static int[] dis = new int[1002]; + static int[] pre = new int[1010]; + + //加双向边 + static void add(int a, int b, int c) { + e[++cnt]=b; + w[cnt]=c; + ne[cnt]=h[a]; + h[a]=cnt; + e[++cnt]=a; + w[cnt]=0; + ne[cnt]=h[b]; + h[b]=cnt; + } + + static ArrayDeque q = new ArrayDeque(); + + //使用bfs寻找增广路 + static boolean bfs() { + Arrays.fill(st, false); + q.clear(); + q.push(s); + st[s] = true; + dis[s] = inf; + while (!q.isEmpty()) { + int x = q.pollFirst(); + for (int i = h[x]; i != 0; i = ne[i]) { + if (w[i] == 0) continue; + int v = e[i]; + if (st[v]) continue; + dis[v] = Math.min(dis[x], w[i]); + pre[v] = i; + q.push(v); + st[v] = true; + if (v == t) return true; + } + } + return false; + } + + static void update() { + int x = t; + while (x != s) { + int v = pre[x]; + w[v] -= dis[t]; + w[v ^ 1] += dis[t]; + x = e[v ^ 1]; + } + ans += dis[t]; + } + + static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + static BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + static StringTokenizer tokenizer = new StringTokenizer(""); + + static String nextLine() throws IOException {// 读取下一行字符串 + return reader.readLine(); + } + + static String next() throws IOException {// 读取下一个字符串 + while (!tokenizer.hasMoreTokens()) { + //如果没有字符了,就是下一个,使用空格拆分, + tokenizer = new StringTokenizer(reader.readLine()); + } + return tokenizer.nextToken(); + } + + static int nextInt() throws IOException {// 读取下一个int型数值 + return Integer.parseInt(next()); + } + + static double nextDouble() throws IOException {// 读取下一个double型数值 + return Double.parseDouble(next()); + } +} diff --git "a/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\217\227\346\254\242\350\277\216\347\232\204\347\211\233.java" "b/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\217\227\346\254\242\350\277\216\347\232\204\347\211\233.java" new file mode 100644 index 0000000000000000000000000000000000000000..0eda787f32336efefc07eda892cbec943055fe38 --- /dev/null +++ "b/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\217\227\346\254\242\350\277\216\347\232\204\347\211\233.java" @@ -0,0 +1,34 @@ +package graph.有向图的强联通分量; + +/** + * + */ +@SuppressWarnings("all") +public class 受欢迎的牛 { + public static void main(String[] args) { + + } + +// static void tarjar(int u) { +// dfu[u] = low[u] = ++time; +// stk[++top] = u; +// in_stk[u] = true; +// for (int i = he[u]; i != 0; i = ne[i]) { +// int j=e[i]; +// if (!dfn[j]){ +// tarjar(j); +// low[u]=Math.min(low[u],low[j]); +// }else if (in_stk[j]) +// low[u]=Math.min(low[u],dfn[j]); +// } +// if (dfn[u]==low[u]){ +// int y; +// ++scc_cnt; +// do { +// y=stk[top--]; +// in_stk[y]=false; +// id[y]=scc_cnt; +// }while (y!=u); +// } +// } +} diff --git "a/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\274\272\350\277\236\351\200\232\345\210\206\351\207\217.md" "b/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\274\272\350\277\236\351\200\232\345\210\206\351\207\217.md" index de97dbddc68669072cf95d9b30a2277b3ae859d1..92b3f7b333ef139b253baec6b7086c7d9925456a 100644 --- "a/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\274\272\350\277\236\351\200\232\345\210\206\351\207\217.md" +++ "b/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\274\272\350\277\236\351\200\232\345\210\206\351\207\217.md" @@ -13,3 +13,12 @@ 后向边 横叉边 SCC强连通分量 + +1.某一点是否在强连通分量里面,存在后向边指向祖先节点, +2.先走到横叉边,横叉边再走到祖先节点 + +基于tarjan求强连通分量(SCC) +引入时间戳 +dfn[u]遍历到u的时间 +low[u]记录从u开始走,所能遍历到的最小时间戳是什么 +u是其所在强连通分量的最高点,等价于dfn[u]==low[u] diff --git "a/ACWing/src/graph/\346\264\233\350\260\267\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215.java" "b/ACWing/src/graph/\346\264\233\350\260\267\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215.java" new file mode 100644 index 0000000000000000000000000000000000000000..966930f816854a636ddaad9354ad8c2f0c0b1d98 --- /dev/null +++ "b/ACWing/src/graph/\346\264\233\350\260\267\344\272\214\345\210\206\345\233\276\346\234\200\345\244\247\345\214\271\351\205\215.java" @@ -0,0 +1,31 @@ +package graph; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.StringTokenizer; + +/** + * + */ +public class 洛谷二分图最大匹配 { + public static void main(String[] args) { + + + } + + static int n, m, N = 510, M = 5000; + static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + static StringTokenizer st = new StringTokenizer(""); + + static String next() throws IOException { + while (!st.hasMoreTokens()) { + st = new StringTokenizer(br.readLine()); + } + return st.nextToken(); + } + + static int nextInt() throws IOException { + return Integer.parseInt(next()); + } +}