Fluid Dynamics
Complejidad temporal: , donde .
Mantenemos una lista enlazada de envolventes convexas de tamaño cada una. Cada actualización y consulta toma tiempo . El TL es bastante ajustado …
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using db = double;
using str = string; // yay python!
using pi = pair<int, int>;
using pl = pair<ll, ll>;
using pd = pair<db, db>;
using vi = vector<int>;
using vb = vector<bool>;
using vl = vector<ll>;
using vd = vector<db>;
using vs = vector<str>;
using vpi = vector<pi>;
using vpl = vector<pl>;
using vpd = vector<pd>;
#define tcT template <class T
#define tcTU tcT, class U
// ^ lol this makes everything look weird but I'll try it
tcT > using V = vector<T>;
tcT, size_t SZ > using AR = array<T, SZ>;
tcT > using PR = pair<T, T>;
// pairs
#define mp make_pair
#define f first
#define s second
// vectors
// oops size(x), rbegin(x), rend(x) need C++17
#define sz(x) int((x).size())
#define bg(x) begin(x)
#define all(x) bg(x), end(x)
#define rall(x) x.rbegin(), x.rend()
#define sor(x) sort(all(x))
#define rsz resize
#define ins insert
#define ft front()
#define bk back()
#define pb push_back
#define eb emplace_back
#define pf push_front
#define lb lower_bound
#define ub upper_bound
tcT > int lwb(V<T> &a, const T &b) { return int(lb(all(a), b) - bg(a)); }
// loops
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define F0R(i, a) FOR(i, 0, a)
#define ROF(i, a, b) for (int i = (b) - 1; i >= (a); --i)
#define R0F(i, a) ROF(i, 0, a)
#define trav(a, x) for (auto &a : x)
const int MOD = 1e9 + 7; // 998244353;
const int MX = 2e5 + 5;
const ll INF = 1e18; // not too close to LLONG_MAX
const ld PI = acos((ld)-1);
const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1}; // for every grid problem!!
mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
// bitwise ops
// also see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
constexpr int pct(int x) { return __builtin_popcount(x); } // # of bits set
constexpr int bits(int x) { // assert(x >= 0); // make C++11 compatible until
// USACO updates ...
return x == 0 ? 0 : 31 - __builtin_clz(x);
} // floor(log2(x))
constexpr int p2(int x) { return 1 << x; }
constexpr int msk2(int x) { return p2(x) - 1; }
ll cdiv(ll a, ll b) {
return a / b + ((a ^ b) > 0 && a % b);
} // divide a by b rounded up
ll fdiv(ll a, ll b) {
return a / b - ((a ^ b) < 0 && a % b);
} // divide a by b rounded down
tcT > bool ckmin(T &a, const T &b) { return b < a ? a = b, 1 : 0; } // set a = min(a,b)
tcT > bool ckmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
tcTU > T fstTrue(T lo, T hi, U f) {
hi++;
assert(lo <= hi); // assuming f is increasing
while (lo < hi) { // find first index such that f is true
T mid = lo + (hi - lo) / 2;
f(mid) ? hi = mid : lo = mid + 1;
}
return lo;
}
tcTU > T lstTrue(T lo, T hi, U f) {
lo--;
assert(lo <= hi); // assuming f is decreasing
while (lo < hi) { // find first index such that f is true
T mid = lo + (hi - lo + 1) / 2;
f(mid) ? lo = mid : hi = mid - 1;
}
return lo;
}
tcT > void remDup(vector<T> &v) { // sort and remove duplicates
sort(all(v));
v.erase(unique(all(v)), end(v));
}
tcTU > void erase(T &t, const U &u) { // don't erase
auto it = t.find(u);
assert(it != end(t));
t.erase(it);
} // element that doesn't exist from (multi)set
// INPUT
#define tcTUU tcT, class... U
tcT > void re(complex<T> &c);
tcTU > void re(pair<T, U> &p);
tcT > void re(V<T> &v);
tcT, size_t SZ > void re(AR<T, SZ> &a);
tcT > void re(T &x) { cin >> x; }
void re(db &d) {
str t;
re(t);
d = stod(t);
}
void re(ld &d) {
str t;
re(t);
d = stold(t);
}
tcTUU > void re(T &t, U &...u) {
re(t);
re(u...);
}
tcT > void re(complex<T> &c) {
T a, b;
re(a, b);
c = {a, b};
}
tcTU > void re(pair<T, U> &p) { re(p.f, p.s); }
tcT > void re(V<T> &x) { trav(a, x) re(a); }
tcT, size_t SZ > void re(AR<T, SZ> &x) { trav(a, x) re(a); }
tcT > void rv(int n, V<T> &x) {
x.rsz(n);
re(x);
}
// TO_STRING
#define ts to_string
str ts(char c) { return str(1, c); }
str ts(const char *s) { return (str)s; }
str ts(str s) { return s; }
str ts(bool b) {
#ifdef LOCAL
return b ? "true" : "false";
#else
return ts((int)b);
#endif
}
tcT > str ts(complex<T> c) {
stringstream ss;
ss << c;
return ss.str();
}
str ts(V<bool> v) {
str res = "{";
F0R(i, sz(v)) res += char('0' + v[i]);
res += "}";
return res;
}
template <size_t SZ> str ts(bitset<SZ> b) {
str res = "";
F0R(i, SZ) res += char('0' + b[i]);
return res;
}
tcTU > str ts(pair<T, U> p);
tcT > str ts(T v) { // containers with begin(), end()
#ifdef LOCAL
bool fst = 1;
str res = "{";
for (const auto &x : v) {
if (!fst) res += ", ";
fst = 0;
res += ts(x);
}
res += "}";
return res;
#else
bool fst = 1;
str res = "";
for (const auto &x : v) {
if (!fst) res += " ";
fst = 0;
res += ts(x);
}
return res;
#endif
}
tcTU > str ts(pair<T, U> p) {
#ifdef LOCAL
return "(" + ts(p.f) + ", " + ts(p.s) + ")";
#else
return ts(p.f) + " " + ts(p.s);
#endif
}
// OUTPUT
tcT > void pr(T x) { cout << ts(x); }
tcTUU > void pr(const T &t, const U &...u) {
pr(t);
pr(u...);
}
void ps() { pr("\n"); } // print w/ spaces
tcTUU > void ps(const T &t, const U &...u) {
pr(t);
if (sizeof...(u)) pr(" ");
ps(u...);
}
// DEBUG
void DBG() { cerr << "]" << endl; }
tcTUU > void DBG(const T &t, const U &...u) {
cerr << ts(t);
if (sizeof...(u)) cerr << ", ";
DBG(u...);
}
#ifdef LOCAL // compile with -DLOCAL, chk -> fake assert
#define dbg(...) \
cerr << "Line(" << __LINE__ << ") -> [" << #__VA_ARGS__ << "]: [", DBG(__VA_ARGS__)
#define chk(...) \
if (!(__VA_ARGS__)) \
cerr << "Line(" << __LINE__ << ") -> function(" << __FUNCTION__ \
<< ") -> CHK FAILED: (" << #__VA_ARGS__ << ")" << "\n", \
exit(0);
#else
#define dbg(...) 0
#define chk(...) 0
#endif
void setPrec() { cout << fixed << setprecision(15); }
void unsyncIO() { cin.tie(0)->sync_with_stdio(0); }
// FILE I/O
void setIn(str s) { freopen(s.c_str(), "r", stdin); }
void setOut(str s) { freopen(s.c_str(), "w", stdout); }
void setIO(str s = "") {
unsyncIO();
setPrec();
// cin.exceptions(cin.failbit);
// throws exception when do smth illegal
// ex. try to read letter into int
if (sz(s)) setIn(s + ".in"), setOut(s + ".out"); // for USACO
}
#pragma GCC optimize("Ofast")
#pragma GCC target("avx2")
// template code
const int BLOCK = 2000;
int N, Q;
ll W;
typedef pl P;
typedef vector<P> vP;
vP fluid;
ll CROSS(const P &a, const P &b) { return a.f * b.s - a.s * b.f; }
ll CROSS(const P &p, const P &a, const P &b) {
return (a.f - p.f) * (b.s - p.s) - (a.s - p.s) * (b.f - p.f);
}
ll cross(int a, int b, int c) { return CROSS(fluid[a], fluid[b], fluid[c]); }
ll dif(int a, int x) { return fluid[x].f * fluid[a].s - fluid[x].s * fluid[a].f; }
ll bs(int *v, const P &p, int lo, int hi) {
auto eval = [&](int x) { return fluid[x].f * p.f + fluid[x].s * p.s; };
while (lo < hi) {
int mid = (lo + hi) / 2;
if (eval(v[mid]) < eval(v[mid + 1])) hi = mid;
else lo = mid + 1;
}
return eval(v[lo]);
}
bool cmp(int a, int b) { return fluid[a] < fluid[b]; }
struct Hull {
int dat[BLOCK], lower[BLOCK];
int dsz = 0, usz = 0, lsz = 0;
ll minDif(int x) { // get min of
pl p = {-fluid[x].s, fluid[x].f};
return bs(lower, p, 0, lsz - 1);
}
bool bad(int x) { return minDif(x) >= W; }
void build() {
vi xord;
F0R(i, dsz) xord.pb(dat[i]);
sort(all(xord), cmp);
usz = lsz = 0;
for (int i : xord) {
while (lsz > 1 && cross(lower[lsz - 2], lower[lsz - 1], i) <= 0) lsz--;
lower[lsz++] = i;
}
}
void prin(int *a, int &b) {
F0R(i, b) dbg(a[i]);
dbg("----");
}
void INS(int *a, int &b, int pos, int label) {
ROF(i, pos + 1, b + 1) a[i] = a[i - 1];
a[pos] = label;
b++;
}
void ERASE(int *a, int &b, int l, int r) {
int dif = r - l;
if (dif <= 0) return;
FOR(i, r, b) a[i - dif] = a[i];
b -= dif;
}
void insLower(int label) {
int pos = lb(lower, lower + lsz, label, cmp) - lower;
if (pos && pos < lsz) {
if (cross(lower[pos - 1], lower[pos], label) >= 0) return;
}
INS(lower, lsz, pos, label);
{
int nex = pos + 1;
while (nex + 1 < lsz && cross(lower[pos], lower[nex], lower[nex + 1]) <= 0)
nex++;
ERASE(lower, lsz, pos + 1, nex);
}
{
int nex = pos - 1;
while (nex > 0 && cross(lower[nex - 1], lower[nex], lower[pos]) <= 0) nex--;
ERASE(lower, lsz, nex + 1, pos);
}
}
void ins(int label) {
int i = dsz;
while (i && dif(dat[i - 1], label) >= W) i--;
INS(dat, dsz, i, label);
insLower(label);
}
};
vector<Hull> hull;
vi NEX, PRE;
int lst = -1;
int num;
int ad() {
hull.pb(Hull());
NEX.pb(-1), PRE.pb(-1);
return sz(hull) - 1;
}
void link(int a, int b) {
NEX[a] = b;
if (b == -1) lst = a;
else PRE[b] = a;
}
int ti = 0;
void split(int cur) {
int SZ = hull[cur].dsz;
assert(SZ <= BLOCK);
if (SZ != BLOCK) return;
int CUR = ad();
int aft = NEX[cur];
link(cur, CUR);
link(CUR, aft);
int *v = hull[cur].dat;
int m = SZ / 2;
++ti;
assert(hull[CUR].dsz == 0);
FOR(i, m, SZ) {
int t = v[i];
hull[CUR].dat[hull[CUR].dsz++] = t;
}
hull[cur].dsz = m;
assert(hull[CUR].dsz == m);
hull[cur].build();
hull[CUR].build(); // split block into two
}
void ins(int v, int c) {
num++;
int label = sz(fluid);
fluid.pb({v, c});
int cur = lst, pre = -1;
while (cur != -1 && hull[cur].bad(label)) {
pre = cur;
cur = PRE[cur];
}
if (cur == -1) {
if (pre == -1) {
assert(sz(fluid) == 1);
lst = pre = ad();
}
cur = pre;
}
hull[cur].ins(label);
split(cur);
}
int get(int k) {
k = num + 1 - k;
assert(k);
for (int cur = lst;; cur = PRE[cur]) {
assert(cur != -1);
int *v = hull[cur].dat, SZ = hull[cur].dsz;
if (SZ >= k) return v[SZ - k];
k -= SZ;
}
exit(5);
}
int main() {
clock_t beg = clock();
setIO();
re(N, Q, W);
F0R(i, N) {
int v, c;
re(v, c);
ins(v, c);
}
dbg("DONE WITH INSERTS", (db)(clock() - beg) / CLOCKS_PER_SEC);
F0R(i, Q) {
str s;
re(s);
if (s == "INSERT") {
int v, c;
re(v, c);
ins(v, c);
} else {
int k;
re(k);
int p = get(k);
ps(fluid[p].f, fluid[p].s);
}
}
dbg((db)(clock() - beg) / CLOCKS_PER_SEC);
}