From 916df8b018ba04612207f2974ef1e80672e08908 Mon Sep 17 00:00:00 2001 From: Departuers <2644631299@qq.com> Date: Tue, 8 Sep 2020 16:12:14 +0800 Subject: [PATCH] c --- ...\350\276\223\345\260\217\347\214\253.java" | 4 +- ...\351\230\265\350\267\235\347\246\273.java" | 2 +- "ACWing/src/IO\345\212\240\351\200\237.java" | 51 +------ ...\347\224\237\346\210\220\346\240\221.java" | 2 +- ...\345\255\231\350\257\242\351\227\256.java" | 10 +- ...\350\207\252\345\212\250\346\234\272.java" | 8 ++ ACWing/src/String/KMP.java | 21 ++- .../String/\346\213\223\345\261\225kmp.java" | 17 +++ .../String/\346\264\233\350\260\267kmp.java" | 53 +++++++ ...\346\240\267\347\232\204\347\211\233.java" | 4 +- .../seg.java" | 56 ++++---- ...\347\202\271\347\211\210\346\234\254.java" | 129 ++++++++++++++++++ 12 files changed, 264 insertions(+), 93 deletions(-) create mode 100644 "ACWing/src/String/AC\350\207\252\345\212\250\346\234\272.java" create mode 100644 "ACWing/src/String/\346\213\223\345\261\225kmp.java" create mode 100644 "ACWing/src/String/\346\264\233\350\260\267kmp.java" create mode 100644 "ACWing/src/\347\272\277\346\256\265\346\240\221/\351\235\231\346\200\201\344\270\273\345\270\255\346\240\221\347\273\223\347\202\271\347\211\210\346\234\254.java" diff --git "a/ACWing/src/DFS/\345\211\252\346\236\235/\350\277\220\350\276\223\345\260\217\347\214\253.java" "b/ACWing/src/DFS/\345\211\252\346\236\235/\350\277\220\350\276\223\345\260\217\347\214\253.java" index 40c90a1..cc30b21 100644 --- "a/ACWing/src/DFS/\345\211\252\346\236\235/\350\277\220\350\276\223\345\260\217\347\214\253.java" +++ "b/ACWing/src/DFS/\345\211\252\346\236\235/\350\277\220\350\276\223\345\260\217\347\214\253.java" @@ -70,7 +70,7 @@ public class 运输小猫 { sum[i] -= w[u]; } } - //k的取值是0~k-1,所以k就是下一辆车 + //k的取值是0~k-1,所以下一次递归k就是下一辆车 sum[k] = w[u]; dfs(u + 1, k + 1); sum[k] = 0; @@ -82,7 +82,7 @@ public class 运输小猫 { * @param u */ static void f(int u) { - if (len >= ans) return; + if (len >= ans) return;//最优性剪枝 if (u == n) { ans = len; System.out.println(Arrays.toString(car));//每辆车放多少个 diff --git "a/ACWing/src/DFS/\345\244\232\346\272\220bfs/\347\237\251\351\230\265\350\267\235\347\246\273.java" "b/ACWing/src/DFS/\345\244\232\346\272\220bfs/\347\237\251\351\230\265\350\267\235\347\246\273.java" index 5686d1a..3c8180e 100644 --- "a/ACWing/src/DFS/\345\244\232\346\272\220bfs/\347\237\251\351\230\265\350\267\235\347\246\273.java" +++ "b/ACWing/src/DFS/\345\244\232\346\272\220bfs/\347\237\251\351\230\265\350\267\235\347\246\273.java" @@ -34,7 +34,7 @@ import static java.lang.System.in; * 找每个点到指定最近的终点 * 显然:多源最短路,求每个点到一堆起点的距离,终点不唯一找出最近,可以转化成单源最短路 * 有一个虚拟头结点,与所有起点有一条边权为0的边, - * 体现在bfs中就是队列中添加所有起点!!! + * 体现在bfs中就是队列中添加所有起点!!!也就是把要到的位置加入对队列作为起点 * 体现在dijkstra就是要真的把那个源点建立出来 */ public class 矩阵距离 { diff --git "a/ACWing/src/IO\345\212\240\351\200\237.java" "b/ACWing/src/IO\345\212\240\351\200\237.java" index 6be03e4..874cbe6 100644 --- "a/ACWing/src/IO\345\212\240\351\200\237.java" +++ "b/ACWing/src/IO\345\212\240\351\200\237.java" @@ -31,8 +31,8 @@ public class IO加速 { public static void main(String[] args) throws IOException { // fff(); // sw(); - dfs(4, 1, new ArrayList()); -// f(); + ///dfs(4, 1, new ArrayList()); + f(); // tokenizer = new StringTokenizer("123123 15412 4312412"); // System.out.println(tokenizer.nextToken()); // System.out.println(tokenizer.nextToken()); @@ -82,53 +82,6 @@ public class IO加速 { } } - static void sw() { - - long s = System.nanoTime(); - for (int i = 0; i < par.length; i++) { - par[i] = i; - } - for (int i = 0; i < par.length; i++) { - union(1, i); - } - long t = System.nanoTime(); - System.out.println((t - s) / 1e8); - - s = System.nanoTime(); - for (int i = 0; i < par.length; i++) { - par[i] = i; - } - for (int i = 0; i < par.length; i++) { - unio(i, 0); - } - t = System.nanoTime(); - System.out.println((t - s) / 1e8); - } - - static void union(int x, int y) { - x = find(x); - y = find(y); - if (x != y) par[x] = y; - } - - static void unio(int x, int y) { - x = fin(x); - y = fin(y); - if (x != y) par[x] = y; - } - - static int find(int x) { - while (x != par[x]) { - par[x] = par[par[x]]; - x = par[x]; - } - return x; - } - - static int fin(int x) { - if (x == par[x]) return x; - return par[x] = fin(par[x]); - } static int[] par = new int[11000000]; diff --git "a/ACWing/src/LCA/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.java" "b/ACWing/src/LCA/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.java" index d846877..9f634e0 100644 --- "a/ACWing/src/LCA/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.java" +++ "b/ACWing/src/LCA/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.java" @@ -8,7 +8,7 @@ import java.util.StringTokenizer; import static java.lang.System.in; /** - * * https://blog.csdn.net/qq_41661919/article/details/86565228 + * https://blog.csdn.net/qq_41661919/article/details/86565228 * https://blog.csdn.net/qq_44828887/article/details/107305636 * 给定一张 N 个点 M 条边的无向图,求无向图的严格次小生成树。 * 设最小生成树的边权之和为sum, diff --git "a/ACWing/src/LCA/\347\245\226\345\255\231\350\257\242\351\227\256.java" "b/ACWing/src/LCA/\347\245\226\345\255\231\350\257\242\351\227\256.java" index b8df333..6ddc312 100644 --- "a/ACWing/src/LCA/\347\245\226\345\255\231\350\257\242\351\227\256.java" +++ "b/ACWing/src/LCA/\347\245\226\345\255\231\350\257\242\351\227\256.java" @@ -63,18 +63,20 @@ public class 祖孙询问 { else if (p == b) System.out.println(2); else System.out.println(0); } - } private static int lca(int a, int b) { if (depth[a] < depth[b]) return lca(b, a); - //a要在b的上面 + //depth[a]>depth[b]也就是a的深度更深,a在下面 + //a往上跳,先跳到根b相同高度 for (int k = 17; k >= 0; k--) { if (depth[up[a][k]] >= depth[b]) { a = up[a][k]; } - }//从高往低跳 + }//跳到一个特别高的位置,会使得up[a][k]=0,而0是不存在的节点,depth[0]=0,不会出错 + //从高往下跳,最终a与b处于同一高度 if (a == b) return a; + //a与b处于同一高度,从高往低枚举,同时跳 for (int k = 17; k >= 0; k--) { if (up[a][k] != up[b][k]) { a = up[a][k]; @@ -127,4 +129,6 @@ public class 祖孙询问 { } } } + + } diff --git "a/ACWing/src/String/AC\350\207\252\345\212\250\346\234\272.java" "b/ACWing/src/String/AC\350\207\252\345\212\250\346\234\272.java" new file mode 100644 index 0000000..d1e0c9a --- /dev/null +++ "b/ACWing/src/String/AC\350\207\252\345\212\250\346\234\272.java" @@ -0,0 +1,8 @@ +package String; + +/** + * KMP解决单模式串,AC自动机=trie+kmp 可以解决多模式串 + */ +public class AC自动机 { + +} diff --git a/ACWing/src/String/KMP.java b/ACWing/src/String/KMP.java index 45d19b1..20282b5 100644 --- a/ACWing/src/String/KMP.java +++ b/ACWing/src/String/KMP.java @@ -1,10 +1,21 @@ package String; -import java.util.Arrays; import java.util.Scanner; /** * https://blog.csdn.net/qq_30277239/article/details/100881221 + *

+ * T是匹配串,P是模式串 + * 假设T[s+1,...s+k]和P[1..k]匹配上了, + * 此时T[s+k+1]!=P[k+1] + * 朴素的做法是回到T[s+2]的位置,和P[1]的位置重新开始比较, + * KMP找到一个最大的x,使得T[s+1,...s+k]的后x个字符和P的前x的字符相同 + * 这部分就是可以匹配上的,O(n+m) + * 又注意到,T[s+1...s+k]=P[1..k] + * 那么我们要求就是一个最大的x,满足P[1..k]的前x个字符,等于它的后x个字符,当然x要小于k + * 这个x记为next[k],这个只与模式串有关 + *

+ * 样例 * 3 * aba * 5 @@ -17,12 +28,11 @@ public class KMP { public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); - p = sc.next().toCharArray(); + p = sc.next().toCharArray();//长度为n的模式串 m = sc.nextInt(); - a = sc.next().toCharArray(); + a = sc.next().toCharArray();//长度为m的文本串 int i = 0, j = 0; init(); - System.out.println(Arrays.toString(ne)); //i是源串,j是匹配串 while (i < m && j < n) { if (j == -1 || a[i] == p[j]) { @@ -31,7 +41,7 @@ public class KMP { j++; } else j = ne[j];//回到适配位置 if (j == n) {//匹配成功!找到了 - j = ne[j]; + j = ne[j];//又开始找下一个 System.out.println(i - n); //找到每个匹配成功的起始位置 } @@ -52,5 +62,4 @@ public class KMP { ne[i] = t + 1; } } - } diff --git "a/ACWing/src/String/\346\213\223\345\261\225kmp.java" "b/ACWing/src/String/\346\213\223\345\261\225kmp.java" new file mode 100644 index 0000000..b7d913f --- /dev/null +++ "b/ACWing/src/String/\346\213\223\345\261\225kmp.java" @@ -0,0 +1,17 @@ +package String; + +/** + * 给定两个字符串S和T(长度分别为n和m) + * 定义extend[i]=S[i..n]与T的最长公共前缀的长度 + * 求extend数组 + * i 1 2 3 4 5 6 7 + * S a b a b a c a + * T a b a c + * extend[i] 3 0 4 0 1 0 1 + * 如果S==T那么extend就是Z数组 + */ +public class 拓展kmp { + public static void main(String[] args) { + + } +} diff --git "a/ACWing/src/String/\346\264\233\350\260\267kmp.java" "b/ACWing/src/String/\346\264\233\350\260\267kmp.java" new file mode 100644 index 0000000..ebef88d --- /dev/null +++ "b/ACWing/src/String/\346\264\233\350\260\267kmp.java" @@ -0,0 +1,53 @@ +package String; + +import java.io.*; +import java.util.StringTokenizer; + +public class 洛谷kmp { + public static void main(String[] args) throws IOException { + a = next().toCharArray(); + p = next().toCharArray(); + init(); + int i = 0, m = a.length, j = 0, n = p.length; + while (i < m && j < n) { + if (j == -1 || p[j] == a[i]) { + i++; + j++; + } else j = ne[j]; + if (j == n) { + bw.write(i - j + 1 + "\n"); + j = ne[j]; + } + } + for (int k = 1; k <= p.length; k++) { + bw.write(ne[k] + " "); + } + bw.flush(); + } + + private static void init() { + ne[0] = -1; + int t = 0; + for (int i = 1; i <= p.length; i++) { + t = ne[i - 1]; + while (t != -1 && p[i - 1] != p[t]) t = ne[t]; + ne[i] = t + 1; + } + } + + static int[] ne = new int[1000]; + static char[] p; + static char[] a; + + static int n; + static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + static StringTokenizer tk = new StringTokenizer(""); + + static String next() throws IOException { + while (!tk.hasMoreTokens()) { + tk = new StringTokenizer(br.readLine()); + } + return tk.nextToken(); + } +} diff --git "a/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\350\260\234\344\270\200\346\240\267\347\232\204\347\211\233.java" "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\350\260\234\344\270\200\346\240\267\347\232\204\347\211\233.java" index 949ffb1..14e5930 100644 --- "a/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\350\260\234\344\270\200\346\240\267\347\232\204\347\211\233.java" +++ "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\350\260\234\344\270\200\346\240\267\347\232\204\347\211\233.java" @@ -33,7 +33,7 @@ import java.util.StringTokenizer; * 1 * 设A1 A2...An * 倒着往前推, - * 那么低An位置,就是第An+1小的数 + * 那么第An位置,就是第An+1小的数 * 第A(i)位置,有A(i)头比它少,就是剩下的第A(i)小的数 * (1)从剩余的数中找到第k小的数 * (2)删除某个数 @@ -63,7 +63,7 @@ public class 谜一样的牛 { add(r, -1); } for (int i = 1; i <= n; i++) { - bw.write(ans[i]+"\n"); + bw.write(ans[i] + "\n"); } bw.flush(); diff --git "a/ACWing/src/\347\272\277\346\256\265\346\240\221/seg.java" "b/ACWing/src/\347\272\277\346\256\265\346\240\221/seg.java" index 588323b..844d5fa 100644 --- "a/ACWing/src/\347\272\277\346\256\265\346\240\221/seg.java" +++ "b/ACWing/src/\347\272\277\346\256\265\346\240\221/seg.java" @@ -27,15 +27,13 @@ public class seg { } static class node { - int l, r; - long sum;//区间和 - int lazy;//懒标记,给当前节点为根的子树中的每一个节点加上lazy(设计不包含根节点) - //只要递归到子区间就pushdown + int l, r, lazy; + long v; - public node(int l, int r, int sum) { + public node(int l, int r, long v) { this.l = l; this.r = r; - this.sum = sum; + this.v = v; } } @@ -52,44 +50,44 @@ public class seg { } private static void pushup(int k) { - tr[k].sum = tr[k << 1].sum + tr[k << 1 | 1].sum; - } - - static void update(int k, int l, int r, int d) { - if (tr[k].l >= l && tr[k].r <= r) { - tr[k].sum += (tr[k].r - tr[k].l + 1) * d; - tr[k].lazy += d; - return; - } - down(k); - int mid = tr[k].l + tr[k].r >> 1; - if (l <= mid) update(k << 1, l, r, d); - if (r > mid) update(k << 1 | 1, l, r, d); - pushup(k); + tr[k].v = tr[k << 1].v + tr[k << 1 | 1].v; } static long query(int k, int l, int r) { if (tr[k].l >= l && tr[k].r <= r) { - return tr[k].sum; + return tr[k].v; } down(k); int mid = tr[k].l + tr[k].r >> 1; - long ans = 0; - if (l <= mid) ans += query(k << 1, l, r); - if (r > mid) ans += query(k << 1 | 1, l, r); - return ans; + long res = 0; + if (l <= mid) res += query(k << 1, l, r); + if (r > mid) res += query(k << 1 | 1, l, r); + return res; } private static void down(int k) { if (tr[k].lazy != 0) { - tr[k << 1].sum += (tr[k << 1].r - tr[k << 1].l + 1) * tr[k].lazy; - tr[k << 1 | 1].sum += (tr[k << 1 | 1].r - tr[k << 1 | 1].l + 1) * tr[k].lazy; - tr[k << 1].lazy += tr[k].lazy; - tr[k << 1 | 1].lazy += tr[k].lazy; + tr[k << 1].v += (tr[k << 1].r - tr[k << 1].l + 1) * tr[k].lazy; + tr[k << 1 | 1].v += (tr[k << 1 | 1].r - tr[k << 1 | 1].l + 1) * tr[k].lazy; + tr[k << 1].lazy = tr[k].lazy; + tr[k << 1 | 1].lazy = tr[k].lazy; tr[k].lazy = 0; } } + static void update(int k, int l, int r, int d) { + if (tr[k].l >= l && tr[k].r <= r) { + tr[k].v += (tr[k].r - tr[k].l + 1) * d; + tr[k].lazy += d; + return; + } + down(k); + int mid = tr[k].l + tr[k].r >> 1; + if (l <= mid) update(k << 1, l, r, d); + if (r > mid) update(k << 1 | 1, l, r, d); + pushup(k); + } + static int N = (int) (1e5 + 2), n, m; static node[] tr = new node[N * 4]; static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); diff --git "a/ACWing/src/\347\272\277\346\256\265\346\240\221/\351\235\231\346\200\201\344\270\273\345\270\255\346\240\221\347\273\223\347\202\271\347\211\210\346\234\254.java" "b/ACWing/src/\347\272\277\346\256\265\346\240\221/\351\235\231\346\200\201\344\270\273\345\270\255\346\240\221\347\273\223\347\202\271\347\211\210\346\234\254.java" new file mode 100644 index 0000000..466d6ed --- /dev/null +++ "b/ACWing/src/\347\272\277\346\256\265\346\240\221/\351\235\231\346\200\201\344\270\273\345\270\255\346\240\221\347\273\223\347\202\271\347\211\210\346\234\254.java" @@ -0,0 +1,129 @@ +package 线段树; + +import java.io.*; +import java.util.Arrays; +import java.util.StringTokenizer; + +import static java.lang.System.in; + +/** + * 不能用废弃 + * https://www.acwing.com/blog/content/487/ + * 静态区间第k大 + * 我们可以建立一颗权值线段树,每个点存储的信息为该值域区间存在的数的个数。 + */ +public class 静态主席树结点版本 { + 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()); + } + + static class seg { + int l, r, v; + + public seg(int l, int r, int v) { + this.l = l; + this.r = r; + this.v = v; + } + } + + static seg[] tr = new seg[200100 * 20]; + + public static void main(String[] args) throws IOException { + n = nextInt(); + m = nextInt(); + for (int i = 1; i <= n; i++) { + a[i] = nextInt(); + d[i] = a[i]; + } + Arrays.sort(d, 1, n + 1); + int len = unique(d, n); + for (int i = 1; i <= n; i++) { + a[i] = Arrays.binarySearch(d, 1, 1 + len, a[i]); + } + T[0] = build(1, len); + int l, r, k; + while (m-- != 0) { + l = nextInt(); + r = nextInt(); + k = nextInt(); + int ans = query(T[l - 1], T[r], l, len, k); + bw.write(d[ans] + "\n"); + } + bw.flush(); + } + + static int[] a = new int[200010]; + static int[] d = new int[200010]; + static int[] T = new int[200010]; + static int tot = 0, n, m; + + static int unique(int[] t, int n) { + int j = 1; + for (int i = 1; i <= n; i++) { + if (j == 1 || t[i] != t[i - 1]) { + t[j++] = t[i]; + } + } + return j; + } + + /** + * 建树, + * + * @param l 左区间 + * @param r + * @return 根节点位置 + */ + static int build(int l, int r) { + int p = ++tot, mid = l + r >> 1; + tr[p] = new seg(l, r, 0); + if (l < r) { + tr[p].l = build(l, mid); + tr[p].r = build(mid + 1, r); + } + return p; + } + + static int update(int pre, int l, int r, int v) { + int p = ++tot, mid = l + r >> 1; + tr[p].l = tr[pre].l; + tr[p].r = tr[pre].r; + tr[p].v = tr[pre].v + 1; + if (l < r) { + //应该更新哪一个值域区间 + if (v <= mid) tr[p].l = update(tr[pre].l, l, mid, v); + else tr[p].r = update(tr[pre].r, mid + 1, r, v); + } + return p; + } + + static int query(int x, int y, int l, int r, int k) { + if (l == r) return l; + //对位相减 + int sum = tr[tr[y].l].v - tr[tr[x].l].v, mid = l + r >> 1; + if (k <= sum) return query(tr[x].l, tr[y].l, l, mid, k); + else return query(tr[x].r, tr[y].r, mid + 1, r, k - sum); + } + +} -- GitLab