forked from tmwilliamlin168/CompetitiveProgramming
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathR067-F.java
More file actions
159 lines (153 loc) · 4.13 KB
/
Copy pathR067-F.java
File metadata and controls
159 lines (153 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
- Note that in order to minimize the total distance traveled, the person will never change directions
- The answer if the person travels from i to j is sum(k=1...m, max(i<=x<=j, b[x][k])) - sum(k=i...(j-1), A_k)
- The trick is to iterate over all i and maintain the answers for each j in a segment tree
- Let's consider what happens when we move the left index for one ticket
- If B = [5, 3, 2, 4, 6], then S (segment tree) = [5, 5, 5, 5, 6] at first
- When we remove the first element, it only affects elements until the next element that is greater than or equal to it
- Thus, we subtract 5 from the first 4 elements in S
- But now, we have to consider the elements that were covered by the 4
- We simply go from the next element and keep iterating over the element that is greater than or equal to it and add them into S
- [X, 0, 0, 0, 6] => [X, 3, 3, 0, 6] => [X, 3, 3, 4, 6]
- We stop when we hit the end or when we hit an element that is greater than or equal to 4, which is 6
- Each time we uncover an element, it takes O(logn) to add to a range to S
- Each element can only be uncovered once, so it is O(nmlogn) total
- Calculating the answer for i=0 at first can be done simply in O(nm)
*/
import java.io.*;
import java.util.*;
public class Main {
static final Reader in = new Reader();
static final PrintWriter out = new PrintWriter(System.out);
public static void main(String[] args) {
int n=in.nextInt(), m=in.nextInt();
long[] a = new long[n];
for(int i=0; i<n-1; ++i)
a[i]=in.nextInt();
long[][] b = new long[n][m];
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
b[i][j]=in.nextInt();
SegTree st = new SegTree(n);
long[] ini = new long[n], mx1 = new long[m];
long ps=0, ans=0;
for(int i=0; i<n; ++i) {
for(int j=0; j<m; ++j)
ini[i]+=mx1[j]=Math.max(b[i][j], mx1[j]);
ini[i]-=ps;
ps+=a[i];
}
st.build(ini);
int[][] nxt = new int[n][m];
for(int i=n-1; i>=0; --i) {
for(int j=0; j<m; ++j) {
nxt[i][j]=i+1;
while(nxt[i][j]<n&&b[nxt[i][j]][j]<b[i][j])
nxt[i][j]=nxt[nxt[i][j]][j];
}
}
ps=0;
for(int i=0; i<n; ++i) {
ans=Math.max(st.get(i, n-1)+ps, ans);
for(int j=0; j<m; ++j) {
st.add(i, nxt[i][j]-1, -b[i][j]);
for(int k=i+1; k<n&&b[k][j]<b[i][j]; k=nxt[k][j])
st.add(k, nxt[k][j]-1, b[k][j]);
}
ps+=a[i];
}
out.println(ans);
out.close();
}
static class SegTree {
int n, l1, r1;
long v;
long[] a, lazy;
SegTree(int n) {
this.n=n;
a = new long[4*n];
lazy = new long[4*n];
}
void build(long[] b) {
build2(1, 0, n-1, b);
}
private void build2(int i, int l2, int r2, long[] b) {
if(l2<r2) {
int mid=(l2+r2)/2;
build2(2*i, l2, mid, b);
build2(2*i+1, mid+1, r2, b);
a[i]=Math.max(a[2*i], a[2*i+1]);
} else
a[i]=b[l2];
}
void add(int l, int r, long x) {
l1=l;
r1=r;
v=x;
add2(1, 0, n-1);
}
private void add2(int i, int l2, int r2) {
if(l1<=l2&&r2<=r1) {
a[i]+=v;
if(l2<r2) {
lazy[2*i]+=v;
lazy[2*i+1]+=v;
}
} else {
int mid=(l2+r2)/2;
push(i*2, l2, mid);
push(i*2+1, mid+1, r2);
if(l1<=mid)
add2(i*2, l2, mid);
if(mid<r1)
add2(i*2+1, mid+1, r2);
a[i]=Math.max(a[i*2], a[i*2+1]);
}
}
void push(int i, int l, int r) {
a[i]+=lazy[i];
if(l<r) {
lazy[2*i]+=lazy[i];
lazy[2*i+1]+=lazy[i];
}
lazy[i]=0;
}
long get(int l, int r) {
l1=l;
r1=r;
return get2(1, 0, n-1);
}
private long get2(int i, int l2, int r2) {
push(i, l2, r2);
if(l1<=l2&&r2<=r1)
return a[i];
else {
int mid=(l2+r2)/2;
long res=Long.MIN_VALUE;
if(l1<=mid)
res = Math.max(get2(2*i, l2, mid), res);
if(mid<r1)
res = Math.max(get2(2*i+1, mid+1, r2), res);
return res;
}
}
}
static class Reader {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
String next() {
while(st==null||!st.hasMoreTokens()) {
try {
st = new StringTokenizer(br.readLine());
} catch(Exception e) {}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong() {
return Long.parseLong(next());
}
}
}