LOJ #3273. 「JOISC 2020 Day1」扫除 题解
Description
平面直角坐标系上一个等腰直角三角形,维护
- 加入
。 - 把
的点横坐标变成 。 - 把
的点纵坐标变成 。 - 查询第
个点现在的位置。
Solution
考虑没有一操作怎么做。
容易发现对于任意时刻都存在一条左上到右下的轮廓线,满足所有点要么在轮廓线上,要么位置没有发生改变。
所以先求出每个点第一次被移动的时刻
如果有一操作,会让某个点在加入的时候在轮廓线下面,导致上面的做法不正确。考虑规避掉一操作。
假设要求出某个点
求答案时进行类似线段树分治的做法,每次将当前线段树节点
时间复杂度:
Code
#include <bits/stdc++.h> // #define int int64_t const int kMaxM = 1.5e6 + 5, kMaxQ = 1e6 + 5; int n, m, q; int x[kMaxM], y[kMaxM], t[kMaxM], pos[kMaxM], ansx[kMaxQ], ansy[kMaxQ]; std::mt19937 rnd(114514); std::vector<int> vec[kMaxQ * 4], unq; struct Query { int op, x, y; Query(int _op = 0, int _x = 0, int _y = 0) : op(_op), x(_x), y(_y) {} } qq[kMaxQ]; struct Node { int ls, rs, val, x, y, tagx, tagy; Node(int _ls = 0, int _rs = 0, int _val = 0, int _x = 0, int _y = 0, int _tagx = 0, int _tagy = 0) : ls(_ls), rs(_rs), val(_val), x(_x), y(_y), tagx(_tagx), tagy(_tagy) {} }; struct FHQTreap { int rt, tot; Node t[kMaxM]; void clear() { for (int i = 1; i <= tot; ++i) t[i] = Node(); rt = tot = 0; } int newnode(int x, int y) { t[++tot] = {0, 0, rnd(), x, y, 0, 0}; return tot; } void addtag(int x, int tagx, int tagy) { if (~tagx) t[x].x = t[x].tagx = tagx; if (~tagy) t[x].y = t[x].tagy = tagy; } void pushdown(int x) { if (t[x].ls) addtag(t[x].ls, t[x].tagx, t[x].tagy); if (t[x].rs) addtag(t[x].rs, t[x].tagx, t[x].tagy); t[x].tagx = t[x].tagy = -1; } int merge(int x, int y) { if (!x || !y) return x + y; pushdown(x), pushdown(y); if (t[x].val < t[y].val) { t[x].rs = merge(t[x].rs, y); return x; } else { t[y].ls = merge(x, t[y].ls); return y; } } void splitx(int x, int vx, int &a, int &b) { // a 的 x <= vx if (!x) return void(a = b = 0); pushdown(x); if (t[x].x <= vx) { a = x, splitx(t[x].rs, vx, t[x].rs, b); } else { b = x, splitx(t[x].ls, vx, a, t[x].ls); } } void splity(int x, int vy, int &a, int &b) { // a 的 y >= vy if (!x) return void(a = b = 0); pushdown(x); if (t[x].y >= vy) { a = x, splity(t[x].rs, vy, t[x].rs, b); } else { b = x, splity(t[x].ls, vy, a, t[x].ls); } } int ins(int x, int y) { int a, b, c, id; id = newnode(x, y); splitx(rt, x, a, c); splity(a, y, a, b); rt = merge(merge(a, id), merge(b, c)); return id; } void pushall(int x) { if (!x) return; pushdown(x); if (t[x].ls) pushall(t[x].ls); if (t[x].rs) pushall(t[x].rs); } } ft; struct SGT { int N, val[kMaxM * 4]; void build(int n) { for (N = 1; N <= n + 1; N <<= 1) {} std::fill_n(val, 2 * N, 1e9); } void update(int x, int v) { for (x += N; x; x >>= 1) val[x] = v; } int query(int l, int r) { if (l > r) return 1e9; int ret = 1e9; for (l += N - 1, r += N + 1; l ^ r ^ 1; l >>= 1, r >>= 1) { if (~l & 1) ret = std::min(ret, val[l ^ 1]); if (r & 1) ret = std::min(ret, val[r ^ 1]); } return ret; } } sgt[2]; void update(int x, int l, int r, int ql, int qr, int id) { if (l > qr || r < ql) return; else if (l >= ql && r <= qr) return void(vec[x].emplace_back(id)); int mid = (l + r) >> 1; update(x << 1, l, mid, ql, qr, id), update(x << 1 | 1, mid + 1, r, ql, qr, id); } void discrete(int l, int r) { unq.clear(); for (int i = l; i <= r; ++i) { if (qq[i].op == 2 || qq[i].op == 3) unq.emplace_back(qq[i].x); } std::sort(unq.begin(), unq.end()); unq.erase(std::unique(unq.begin(), unq.end()), unq.end()); } int getid(int x) { return std::lower_bound(unq.begin(), unq.end(), x) - unq.begin() + 1; } void solve(int x, int l, int r) { static std::vector<int> vv[kMaxM]; ft.clear(); discrete(l, r); sgt[0].build(unq.size()), sgt[1].build(unq.size()); for (int i = r; i >= l; --i) { if (qq[i].op == 2) sgt[0].update(getid(qq[i].x), i); else if (qq[i].op == 3) sgt[1].update(getid(qq[i].x), i); } for (auto i : vec[x]) { int p = std::min(sgt[0].query(getid(ansy[i]), getid(n - ansx[i] + 1) - 1), sgt[1].query(getid(ansx[i]), getid(n - ansy[i] + 1) - 1)); if (p <= r) vv[p].emplace_back(i); } for (int i = l; i <= r; ++i) { int x, y, z; if (qq[i].op == 2) { ft.splitx(ft.rt, n - qq[i].x, x, z); ft.splity(x, qq[i].x + 1, x, y); if (y) ft.addtag(y, n - qq[i].x, -1); ft.rt = ft.merge(ft.merge(x, y), z); } else if (qq[i].op == 3) { ft.splitx(ft.rt, qq[i].x, x, z); ft.splity(x, n - qq[i].x + 1, x, y); if (y) ft.addtag(y, -1, n - qq[i].x); ft.rt = ft.merge(ft.merge(x, y), z); } for (auto id : vv[i]) { if (qq[i].op == 2) ansx[id] = std::max(ansx[id], n - qq[i].x), assert(ansy[id] <= qq[i].x); else ansy[id] = std::max(ansy[id], n - qq[i].x), assert(ansx[id] <= qq[i].x); pos[id] = ft.ins(ansx[id], ansy[id]); } } ft.pushall(ft.rt); for (int i = l; i <= r; ++i) { for (auto id : vv[i]) { ansx[id] = ft.t[pos[id]].x; ansy[id] = ft.t[pos[id]].y; } } for (int i = l; i <= r; ++i) vv[i].clear(); for (auto i : vec[x]) pos[i] = 0; if (l != r) { int mid = (l + r) >> 1; solve(x << 1, l, mid), solve(x << 1 | 1, mid + 1, r); } } void dickdreamer() { std::cin >> n >> m >> q; for (int i = 1; i <= m; ++i) { std::cin >> x[i] >> y[i]; t[i] = 1; } for (int i = 1; i <= q; ++i) { std::cin >> qq[i].op; if (qq[i].op == 1) { std::cin >> qq[i].x; ansx[i] = x[qq[i].x], ansy[i] = y[qq[i].x]; update(1, 1, q, t[qq[i].x], i, i); } else if (qq[i].op == 2) { std::cin >> qq[i].x; } else if (qq[i].op == 3) { std::cin >> qq[i].x; } else { std::cin >> qq[i].x >> qq[i].y; t[++m] = i, x[m] = qq[i].x, y[m] = qq[i].y; } } solve(1, 1, q); for (int i = 1; i <= q; ++i) if (qq[i].op == 1) std::cout << ansx[i] << ' ' << ansy[i] << '\n'; } int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; // std::cin >> T; while (T--) dickdreamer(); // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n"; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步