Skip to Content

Salary Queries

Solución 1

Como se menciona en el módulo, se puede aplicar compresión de coordenadas antes de usar un Árbol de Segmentos o un BIT.

Quedarse con arreglos (o vectors) siempre que sea posible; usar un map en su lugar puede dar TLE.

#include <bits/stdc++.h> using namespace std; using ll = long long; const int MX = 4e5 + 5; ll bit[MX]; vector<int> vals; int n, q; void upd(int i, int val) { for (; i <= MX; i += i & (-i)) { bit[i] += val; } } void ad(int x, int b) { int ind = upper_bound(vals.begin(), vals.end(), x) - vals.begin(); upd(ind, b); } ll sum(int x) { ll res = 0; for (; x; x -= x & (-x)) { res += bit[x]; } return res; } ll query(int x) { int ind = upper_bound(vals.begin(), vals.end(), x) - vals.begin(); return sum(ind); } int main() { cin >> n >> q; vector<int> ar(n); for (int i = 0; i < n; i++) { cin >> ar[i]; } vals = ar; vector<array<int, 3>> rec; for (int i = 0; i < q; i++) { char t; int a, b; cin >> t >> a >> b; rec.push_back({t == '?', a, b}); if (t == '!') vals.push_back(b); } sort(vals.begin(), vals.end()); vals.erase(unique(vals.begin(), vals.end()), vals.end()); for (int i = 0; i < n; i++) { ad(ar[i], 1); } for (auto u : rec) { u[1]--; if (u[0] == 0) { ad(ar[u[1]], -1); ar[u[1]] = u[2]; ad(ar[u[1]], 1); } else { cout << query(u[2]) - query(u[1]) << '\n'; } } }
import java.io.*; import java.util.*; // Aprovechamos que el número total de salarios únicos, incluyendo las consultas y // el arreglo de entrada, no es más que n (2e5) + 2 * q (2e5), que es 6*10^5. // Así no hay que preocuparse por salarios en el rango 1e9: los comprimimos. public class Salary_Queries { static Reader fr = new Reader(); static PrintWriter out = new PrintWriter(System.out); static long[] list; static long[] Seq; static HashMap<Long, Integer> map; public static void main(String[] args) throws java.lang.Exception { int n = fr.nextInt(); int q = fr.nextInt(); // Arreglo de tamaño fijo evita el overhead de redimensionar ArrayList y el autoboxing de Long. list = new long[n + (q << 1)]; int ptr = 0; long[] arr = new long[n]; for (int i = 0; i < n; i++) { arr[i] = fr.nextLong(); list[ptr++] = arr[i]; } long[][] query = new long[q][3]; for (int i = 0; i < q; i++) { char ch = fr.nextChar(); long a = fr.nextLong(); long b = fr.nextLong(); if (ch == '!') { query[i][0] = 0; query[i][1] = a - 1; query[i][2] = b; list[ptr++] = b; } else { query[i][0] = 1; query[i][1] = a; query[i][2] = b; list[ptr++] = a; list[ptr++] = b; } } // Paso de compresión // Inicio Arrays.sort(list, 0, ptr); int cnt = 0; long prev = 0; map = new HashMap<>(); for (int i = 0; i < ptr; i++) { if (prev != list[i]) map.put(list[i], cnt++); prev = list[i]; } // Fin BIT bt = new BIT(cnt); for (long ele : arr) { bt.update(map.get(ele), 1); } StringBuilder SB = new StringBuilder(); for (long[] qr : query) { if (qr[0] == 0) { bt.update(map.get(arr[(int)qr[1]]), -1); arr[(int)qr[1]] = qr[2]; bt.update(map.get(arr[(int)qr[1]]), 1); } else { int ans = bt.get(map.get(qr[1]), map.get(qr[2])); SB.append(ans).append('\n'); } } out.println(SB.to_string()); out.close(); } // BeginCodeSnip{Reader} static class Reader { private final int BUFFER_SIZE = 1 << 16; private DataInputStream din; private byte[] buffer; private int bufferPointer, bytesRead; public Reader() { din = new DataInputStream(System.in); buffer = new byte[BUFFER_SIZE]; bufferPointer = bytesRead = 0; } // Lee el siguiente entero de la entrada public int nextInt() throws IOException { int ret = 0; byte c = read(); while (c <= ' ') { c = read(); } boolean neg = (c == '-'); if (neg) c = read(); do { ret = ret * 10 + c - '0'; } while ((c = read()) >= '0' && c <= '9'); return neg ? -ret : ret; } // Lee el siguiente long de la entrada public long nextLong() throws IOException { long ret = 0; byte c = read(); while (c <= ' ') { c = read(); } boolean neg = (c == '-'); if (neg) c = read(); do { ret = ret * 10 + c - '0'; } while ((c = read()) >= '0' && c <= '9'); return neg ? -ret : ret; } public char nextChar() throws IOException { byte c = read(); while (c <= ' ') { c = read(); } return (char)c; } // Lee el siguiente byte del buffer private byte read() throws IOException { if (bufferPointer == bytesRead) fillBuffer(); return buffer[bufferPointer++]; } // Llena el buffer con datos nuevos private void fillBuffer() throws IOException { bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE); if (bytesRead == -1) buffer[0] = -1; } } // EndCodeSnip public static int max(int a, int b) { return Math.max(a, b); } public static int min(int a, int b) { return Math.min(a, b); } public static long max(long a, long b) { return Math.max(a, b); } public static long min(long a, long b) { return Math.min(a, b); } } class BIT { int[] bit; int size; public BIT(int n) { this.size = n; bit = new int[n + 1]; } int sum(int r) { int res = 0; for (; r >= 0; r = (r & (r + 1)) - 1) { res += bit[r]; } return res; } void update(int x, int delta) { for (; x < size; x |= x + 1) { bit[x] += delta; } } int get(int l, int r) { return sum(r) - sum(l - 1); } }

Aquí hay una solución similar con un map que pasa ligeramente por debajo del límite de tiempo.

#include <bits/stdc++.h> using namespace std; // BeginCodeSnip{Binary Indexed Tree (from the module)} template <class T> class BIT { private: int size; vector<T> bit; vector<T> arr; public: BIT(int size) : size(size), bit(size + 1), arr(size) {} void set(int ind, T val) { add(ind, val - arr[ind]); } void add(int ind, T val) { arr[ind] += val; ind++; for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } } T pref_sum(int ind) { ind++; T total = 0; for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } return total; } T sum(int ind_left, int ind_right) { return pref_sum(ind_right) - pref_sum(ind_left - 1); } }; // EndCodeSnip int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int n, q; cin >> n >> q; vector<int> coords; map<int, int> compr; vector<int> p(n + 1); for (int i = 1; i <= n; i++) { cin >> p[i]; coords.push_back(p[i]); } vector<pair<char, pair<int, int>>> queries; for (int i = 0; i < q; i++) { char c; cin >> c; int a, b; cin >> a >> b; coords.push_back(a); coords.push_back(b); queries.push_back({c, {a, b}}); } sort(coords.begin(), coords.end()); const int num_coords = coords.size() + 1; BIT<int> bit(num_coords); for (int i = 0; i < num_coords - 1; i++) compr[coords[i]] = i; for (int i = 1; i <= n; i++) { p[i] = compr[p[i]]; bit.add(p[i], 1); } for (const auto &[type, vals] : queries) { if (type == '!') { int k = vals.first; int x = compr[vals.second]; bit.add(p[k], -1); bit.add(x, 1); p[k] = x; } else { cout << bit.sum(compr[vals.first], compr[vals.second]) << '\n'; } } }

Solución 2

¡Simplemente usar indexed set!

#include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> using namespace std; using namespace __gnu_pbds; typedef pair<int, int> pii; template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>; #define FOR(i, a, b) for (int i = a; i < (b); i++) #define F0R(i, a) for (int i = 0; i < (a); i++) const int INF = 1000000007; int n, q, a[200001]; Tree<pii> o; int main() { ios_base::sync_with_stdio(0); cin.tie(0); cin >> n >> q; FOR(i, 1, n + 1) { cin >> a[i]; o.insert({a[i], i}); } F0R(i, q) { char c; cin >> c; if (c == '!') { int x, y; cin >> x >> y; o.erase({a[x], x}); a[x] = y; o.insert({a[x], x}); } else { int x, y; cin >> x >> y; cout << o.order_of_key({y, INF}) - o.order_of_key({x - 1, INF}) << "\n"; } } }