You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
3.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_05_2_week;
import java.util.Arrays;
// 来自字节
// 一共有n个人从左到右排列依次编号0~n-1
// h[i]是第i个人的身高
// v[i]是第i个人的分数
// 要求从左到右选出一个子序列,在这个子序列中的人,从左到右身高是不下降的
// 返回所有符合要求的子序列中,分数最大累加和是多大
// n <= 10的5次方, 1 <= h[i] <= 10的9次方, 1 <= v[i] <= 10的9次方
public class Code03_SortedSubsequenceMaxSum {
// 为了测试
// 绝对正确的暴力方法
public static int right(int[] h, int[] v) {
return process(h, v, 0, 0);
}
public static int process(int[] h, int[] v, int index, int preValue) {
if (index == h.length) {
return 0;
}
int p1 = process(h, v, index + 1, preValue);
int p2 = h[index] >= preValue ? (v[index] + process(h, v, index + 1, h[index])) : 0;
return Math.max(p1, p2);
}
// 正式方法
// 时间复杂度O(N * logN)
public static int maxSum(int[] h, int[] v) {
int n = h.length;
int[] rank = new int[n];
for (int i = 0; i < n; i++) {
rank[i] = h[i];
}
Arrays.sort(rank);
SegmentTree st = new SegmentTree(n);
for (int i = 0; i < n; i++) {
int height = rank(rank, h[i]);
// 1~height max
st.update(height, st.max(height) + v[i]);
}
return st.max(n);
}
// [150, 152, 160, 175] 160
// 1 2 3 4
// 3
public static int rank(int[] rank, int num) {
int l = 0;
int r = rank.length - 1;
int m = 0;
int ans = 0;
while (l <= r) {
m = (l + r) / 2;
if (rank[m] >= num) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans + 1;
}
public static class SegmentTree {
private int n;
private int[] max;
private int[] update;
public SegmentTree(int maxSize) {
n = maxSize + 1;
max = new int[n << 2];
update = new int[n << 2];
Arrays.fill(update, -1);
}
public void update(int index, int c) {
update(index, index, c, 1, n, 1);
}
public int max(int right) {
return max(1, right, 1, n, 1);
}
private void pushUp(int rt) {
max[rt] = Math.max(max[rt << 1], max[rt << 1 | 1]);
}
private void pushDown(int rt, int ln, int rn) {
if (update[rt] != -1) {
update[rt << 1] = update[rt];
max[rt << 1] = update[rt];
update[rt << 1 | 1] = update[rt];
max[rt << 1 | 1] = update[rt];
update[rt] = -1;
}
}
private void update(int L, int R, int C, int l, int r, int rt) {
if (L <= l && r <= R) {
max[rt] = C;
update[rt] = C;
return;
}
int mid = (l + r) >> 1;
pushDown(rt, mid - l + 1, r - mid);
if (L <= mid) {
update(L, R, C, l, mid, rt << 1);
}
if (R > mid) {
update(L, R, C, mid + 1, r, rt << 1 | 1);
}
pushUp(rt);
}
private int max(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
return max[rt];
}
int mid = (l + r) >> 1;
pushDown(rt, mid - l + 1, r - mid);
int ans = 0;
if (L <= mid) {
ans = Math.max(ans, max(L, R, l, mid, rt << 1));
}
if (R > mid) {
ans = Math.max(ans, max(L, R, mid + 1, r, rt << 1 | 1));
}
return ans;
}
}
// 为了测试
public static int[] randomArray(int n, int v) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * v) + 1;
}
return ans;
}
// 为了测试
public static void main(String[] args) {
int N = 30;
int V = 100;
int testTime = 20000;
System.out.println("测试开始");
for (int i = 0; i < testTime; i++) {
int n = (int) (Math.random() * N) + 1;
int[] h = randomArray(n, V);
int[] v = randomArray(n, V);
if (right(h, v) != maxSum(h, v)) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
}
}