【题目链接】
【思路要点】
- 求解不含资源点的矩形个数,用总共的矩形个数减之,得到答案。
- 考虑扫描线,从上至下枚举矩形的下边界,记每一个横坐标\(x\)的资源点最近一次出现在\((x,Depth_x)\)处。
- 维护一棵笛卡尔树(Treap),使得父节点的\(Depth\)始终大于子节点的\(Depth\),记每个点的子树大小为\(Size_x\)。
- 此时,有\(Ans=\sum_{i=1}^{C}(Depth_{father_i}-Depth_i)*\binom{Size_i+1}{2}\),其中\(Ans\)代表以当前纵坐标为下边界的不含资源点的矩形的个数。
- 现在只存在两种操作,将扫描线下移和将某个点的\(Depth\)修改为扫描线的纵坐标,由于数据随机,树高是\(O(LogC)\)的,暴力旋转即可。显然,在这个过程中,我们也可以顺便维护\(Ans\)。
- 时间复杂度\(O(NLogC+R+C)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 100005; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct Treap { struct Node { int father, child[2]; int depth, size; long long val; } a[MAXN]; int root, cur, n; long long sum; void update(int root) { a[root].size = 1; if (a[root].child[0]) a[root].size += a[a[root].child[0]].size; if (a[root].child[1]) a[root].size += a[a[root].child[1]].size; sum -= a[root].val; a[root].val = (a[root].size + 1ll) * a[root].size / 2 * (a[a[root].father].depth - a[root].depth); sum += a[root].val; } void build(int fa, int &root, int l, int r) { root = (l + r) / 2; a[root].father = fa; a[root].size = 1; a[root].depth = 0; if (root > l) build(root, a[root].child[0], l, root - 1); if (root < r) build(root, a[root].child[1], root + 1, r); update(root); } void init(int x) { root = sum = 0; n = x; build(0, a[root].child[1], 1, n); } void move() { cur++; a[root].depth++; if (a[root].child[0]) update(a[root].child[0]); if (a[root].child[1]) update(a[root].child[1]); } bool get(int x) {return x == a[a[x].father].child[1]; } void reset(int x) { static int pos[MAXN]; int cnt = 0; a[x].depth = cur; while (a[x].depth > a[a[x].father].depth) { int f = a[x].father, g = a[f].father; bool tmp = get(x), tnp = get(f); a[f].child[tmp] = a[x].child[tmp ^ 1]; a[a[x].child[tmp ^ 1]].father = f; a[x].child[tmp ^ 1] = f; a[f].father = x; a[x].father = g; a[g].child[tnp] = x; pos[++cnt] = f; } pos[++cnt] = x; for (int i = 1; i <= cnt; i++) { update(pos[i]); if (a[pos[i]].child[0]) update(a[pos[i]].child[0]); if (a[pos[i]].child[1]) update(a[pos[i]].child[1]); } } long long query() { return sum; } } T; int n, m, k; vector <int> a[MAXN]; int main() { read(n), read(m), read(k); for (int i = 1; i <= k; i++) { int x, y; read(x), read(y); a[x].push_back(y); } T.init(m); long long ans = (n + 1ll) * n / 2 * (m + 1ll) * m / 2; for (int i = 1; i <= n; i++) { T.move(); for (unsigned j = 0; j < a[i].size(); j++) T.reset(a[i][j]); ans -= T.query(); } writeln(ans); return 0; }