Skip to content

Improved task 3165 #1857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,125 +1,77 @@
package g3101_3200.s3165_maximum_sum_of_subsequence_with_non_adjacent_elements;

// #Hard #Array #Dynamic_Programming #Divide_and_Conquer #Segment_Tree
// #2024_06_02_Time_1927_ms_(87.75%)_Space_82.1_MB_(5.31%)

import java.util.stream.Stream;
// #2024_11_09_Time_64_ms_(100.00%)_Space_64.1_MB_(97.01%)

public class Solution {
private static final int YY = 0;
private static final int YN = 1;
private static final int NY = 2;
private static final int NN = 3;
private static final int MOD = 1_000_000_007;

public int maximumSumSubsequence(int[] nums, int[][] queries) {
int ans = 0;
SegTree segTree = new SegTree(nums);
for (int[] q : queries) {
int idx = q[0];
int val = q[1];
segTree.update(idx, val);
ans = (ans + segTree.getMax()) % MOD;
long[][] tree = build(nums);
long result = 0;
for (int i = 0; i < queries.length; ++i) {
result += set(tree, queries[i][0], queries[i][1]);
result %= MOD;
}
return ans;
return (int) result;
}

static class SegTree {
private static class Record {
int takeFirstTakeLast;
int takeFirstSkipLast;
int skipFirstSkipLast;
int skipFirstTakeLast;

public Integer getMax() {
return Stream.of(
this.takeFirstSkipLast,
this.takeFirstTakeLast,
this.skipFirstSkipLast,
this.skipFirstTakeLast)
.max(Integer::compare)
.orElse(null);
}

public Integer skipLast() {
return Stream.of(this.takeFirstSkipLast, this.skipFirstSkipLast)
.max(Integer::compare)
.orElse(null);
}

public Integer takeLast() {
return Stream.of(this.skipFirstTakeLast, this.takeFirstTakeLast)
.max(Integer::compare)
.orElse(null);
}
private static long[][] build(int[] nums) {
final int len = nums.length;
int size = 1;
while (size < len) {
size <<= 1;
}

private final Record[] seg;
private final int[] nums;

public SegTree(int[] nums) {
this.nums = nums;
seg = new Record[4 * nums.length];
for (int i = 0; i < 4 * nums.length; ++i) {
seg[i] = new Record();
}
build(0, nums.length - 1, 0);
long[][] tree = new long[size * 2][4];
for (int i = 0; i < len; ++i) {
tree[size + i][YY] = nums[i];
}

private void build(int i, int j, int k) {
if (i == j) {
seg[k].takeFirstTakeLast = nums[i];
return;
}
int mid = (i + j) >> 1;
build(i, mid, 2 * k + 1);
build(mid + 1, j, 2 * k + 2);
merge(k);
}

// merge [2*k+1, 2*k+2] into k
private void merge(int k) {
seg[k].takeFirstSkipLast =
for (int i = size - 1; i > 0; --i) {
tree[i][YY] =
Math.max(
seg[2 * k + 1].takeFirstSkipLast + seg[2 * k + 2].skipLast(),
seg[2 * k + 1].takeFirstTakeLast + seg[2 * k + 2].skipFirstSkipLast);

seg[k].takeFirstTakeLast =
tree[2 * i][YY] + tree[2 * i + 1][NY],
tree[2 * i][YN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY]));
tree[i][YN] =
Math.max(
seg[2 * k + 1].takeFirstSkipLast + seg[2 * k + 2].takeLast(),
seg[2 * k + 1].takeFirstTakeLast + seg[2 * k + 2].skipFirstTakeLast);

seg[k].skipFirstTakeLast =
tree[2 * i][YY] + tree[2 * i + 1][NN],
tree[2 * i][YN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN]));
tree[i][NY] =
Math.max(
seg[2 * k + 1].skipFirstSkipLast + seg[2 * k + 2].takeLast(),
seg[2 * k + 1].skipFirstTakeLast + seg[2 * k + 2].skipFirstTakeLast);

seg[k].skipFirstSkipLast =
tree[2 * i][NY] + tree[2 * i + 1][NY],
tree[2 * i][NN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY]));
tree[i][NN] =
Math.max(
seg[2 * k + 1].skipFirstSkipLast + seg[2 * k + 2].skipLast(),
seg[2 * k + 1].skipFirstTakeLast + seg[2 * k + 2].skipFirstSkipLast);
}

// child -> parent
public void update(int idx, int val) {
int i = 0;
int j = nums.length - 1;
int k = 0;
update(idx, val, k, i, j);
}

private void update(int idx, int val, int k, int i, int j) {
if (i == j) {
seg[k].takeFirstTakeLast = val;
return;
}
int mid = (i + j) >> 1;
if (idx <= mid) {
update(idx, val, 2 * k + 1, i, mid);
} else {
update(idx, val, 2 * k + 2, mid + 1, j);
}
merge(k);
tree[2 * i][NY] + tree[2 * i + 1][NN],
tree[2 * i][NN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN]));
}
return tree;
}

public int getMax() {
return seg[0].getMax();
private static long set(long[][] tree, int idx, int val) {
int size = tree.length / 2;
tree[size + idx][YY] = val;
for (int i = (size + idx) / 2; i > 0; i /= 2) {
tree[i][YY] =
Math.max(
tree[2 * i][YY] + tree[2 * i + 1][NY],
tree[2 * i][YN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY]));
tree[i][YN] =
Math.max(
tree[2 * i][YY] + tree[2 * i + 1][NN],
tree[2 * i][YN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN]));
tree[i][NY] =
Math.max(
tree[2 * i][NY] + tree[2 * i + 1][NY],
tree[2 * i][NN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY]));
tree[i][NN] =
Math.max(
tree[2 * i][NY] + tree[2 * i + 1][NN],
tree[2 * i][NN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN]));
}
return Math.max(tree[1][YY], Math.max(tree[1][YN], Math.max(tree[1][NY], tree[1][NN])));
}
}
Loading