CSES time limits are actually so cancerous for java. I had to literally binary search for a viable max nodes for my Concert Tickets solution to work. However, in the end, my radix trie did indeed work! With 0.99 s on test case 5, I barely scrape by with another ac on these absolutely cancerous time constraints. If this didn't work, I was going to grab the FastIO from kattis and see if the few ms from that would save me. If that failed, then reading System.in.read(byte[]) would have to be my life.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
public class ticketmeisterofconcert {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out);
Tokenizer tr = new Tokenizer(in.readLine());
IntegerMultiSetTree imst = new IntegerMultiSetTree();
int n = tr.intToken();
int m = tr.intToken();
int[] c = new int[m];
tr = new Tokenizer(in.readLine());
for (int i = 0; i < n; ++i) imst.add(tr.intToken());
tr = new Tokenizer(in.readLine());
for (int i = 0; i < m; ++i) c[i] = tr.intToken();
int[] pay = new int[m];
for (int i = 0; i < m; ++i) {
Integer q = imst.floor(c[i]);
pay[i] = q;
if (q != -1)imst.remove(q);
}
for (int uwu : pay) out.println(uwu);
out.flush();
}
static class Tokenizer extends StringTokenizer {
public Tokenizer(String in) { super(in); }
public int intToken() { return Integer.parseInt(this.nextToken()); }
public long longToken() { return Long.parseLong(this.nextToken()); }
public double doubleToken() { return Double.parseDouble(this.nextToken()); }
}
static class IntegerMultiSetTree {
static final int MAX_BITS = 30;
static final int MAX_NODES = 5_360_000;
int[] tree = new int[MAX_NODES*2];
int[] count = new int[MAX_NODES];
int ptr = 0;
public void add(int a) {
int t = 0;
for (int i = 0; i < MAX_BITS; ++i) {
int q = (a >>> MAX_BITS-1-i) & 1;
if (tree[t+q] == 0) {
tree[t+q] = 2 * ++ptr;
}
++count[t];
t = tree[t+q];
}
++count[t];
}
public void remove(int a) {
int t = 0;
--count[t];
for (int i = 0; i < MAX_BITS; ++i) {
int q = (a >>> MAX_BITS-1-i) & 1;
int n = tree[t+q];
if (--count[n] == 0) tree[t+q] = 0;
if (tree[t+q] == 0) {
return;
}
t = tree[t+q];
}
}
public int floor(int a) {
int[] t = new int[MAX_BITS+1];
return dfs(t, a, 0, 0);
}
private int dfs(int[] t, int a, int q, int uwu) {
if (q == MAX_BITS) return uwu;
for (int i = 1; i >= 0; --i) {
if (uwu + (i << MAX_BITS-1-q) <= a) {
if (tree[t[q]+i] == 0) continue;
t[q+1] = tree[t[q]+i];
int b;
if ((b = dfs(t, a, q+1, uwu + (i << MAX_BITS-1-q))) != -1) return b;
}
}
return -1;
}
}
}








I'd very honestly recommend using c++ for cp instead of java, using c++ is not that hard for cp, if you already know java. Boxing also impacts performance a lot, also the fact that it's a JIT'd language, but the JIT does not really have time to kick in the time limits given in CP, so you are working with sub-par code generated.
Main drawbacks of cp like UB and dangling pointers are not that difficult manage in context of cp (actual software is another case)
The views api of c++20 makes it much more tolerable to use too
I already know all the drawbacks of using Java, but I’m a bit too lazy for a while to do the switch. Thanks for the rec though!
recursive though?
Well, if recursive has too much overhead or stack overflows, just write a custom stack and work through it using a while loop.