Problem Info
Question
Is my algorithm wrong, or is Java just slow? Oddly enough, it seems to pass the last test case.
What I’ve Tried
I’ve downloaded the test data to see how many times the inner while loop in my code runs, and it’s never gone over the single-digit millions.
My Work
import java.io.*;
import java.util.*;
public class Mountains {
public static void main(String[] args) throws IOException {
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
int mtnNum = Integer.parseInt(read.readLine());
int[] mtns = Arrays.stream(read.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
assert mtns.length == mtnNum;
int pairNum = 0;
TreeSet<Slope>[] slopes = new TreeSet[mtnNum];
for (int m = 0; m < mtnNum; m++) {
slopes[m] = new TreeSet<>();
for (int next = m + 1; next < mtnNum; next++) {
double slope = (double) (mtns[next] - mtns[m]) / (next - m);
if (next == m + 1 || slope >= slopes[m].last().slope) {
slopes[m].add(new Slope(next, slope));
pairNum++;
}
}
}
long total = 0;
int queryNum = Integer.parseInt(read.readLine());
StringBuilder ans = new StringBuilder();
for (int q = 0; q < queryNum; q++) {
StringTokenizer query = new StringTokenizer(read.readLine());
int ind = Integer.parseInt(query.nextToken()) - 1;
int amt = Integer.parseInt(query.nextToken());
mtns[ind] += amt;
pairNum -= slopes[ind].size();
// yes, this is the exact same loop used just 10 lines above
slopes[ind] = new TreeSet<>();
for (int next = ind + 1; next < mtnNum; next++) {
double slope = (double) (mtns[next] - mtns[ind]) / (next - ind);
if (next == ind + 1 || slope >= slopes[ind].last().slope) {
slopes[ind].add(new Slope(next, slope));
}
}
pairNum += slopes[ind].size();
for (int m = 0; m < ind; m++) {
double slope = (double) (mtns[ind] - mtns[m]) / (ind - m);
Slope obj = new Slope(ind, slope);
Slope compTo = slopes[m].lower(obj);
if (compTo != null && compTo.slope > slope) {
continue;
}
pairNum -= slopes[m].size();
slopes[m].remove(obj); // because of how the treeset works
slopes[m].add(obj);
while (true) {
compTo = slopes[m].higher(obj);
if (compTo == null || compTo.slope >= slope) {
break;
}
slopes[m].remove(compTo);
total++;
}
pairNum += slopes[m].size();
}
ans.append(pairNum).append('\n');
}
System.out.print(ans);
System.out.println(total);
}
private static class Slope implements Comparable<Slope> {
public int to;
public double slope;
public Slope(int to, double slope) {
this.to = to;
this.slope = slope;
}
@Override
public int compareTo(Slope o) { return to - o.to; }
@Override
public String toString() { return String.format("(%d,%f)", to, slope); }
}
}
It maintains a monotonic set of slopes for each mountain.