2019ICPC南京网络赛A(离线树状数组)
分析:一次询问可以分为四次前缀询问,将每次询问按照y升序排序,维护一个x上的树状数组就行了。难点在于计算对应点的值(不会~?~)。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 5; ll bit[maxn], ans[maxn]; struct node { int f, x, y, id, k; friend bool operator<(node a, node b) { if (a.y == b.y) { if (a.x == b.x) return abs(a.f) < abs(b.f); else return a.x < b.x; } else return a.y < b.y; } } a[maxn]; int realv(ll n) { int tmp = 0; while (n) tmp += n % 10, n /= 10; return tmp; } ll index(ll y, ll x, ll n) { ll mid = (n + 1) / 2; ll p = max(abs(x - mid), abs(y - mid)); ll ans = n * n - (1 + p) * p * 4; ll sx = mid + p, sy = mid + p; if (x == sx && y == sy) return ans; else { if (y == sy || x == sx - 2 * p) return ans + abs(x - sx) + abs(y - sy); else return ans + 8 * p - abs(x - sx) - abs(y - sy); } } ll sum(int x) { ll an = 0; while (x) { an += bit[x]; x -= x & -x; } return an; } void update(int id, int n, ll k) { while (id <= n) { bit[id] += k; id += id & -id; } } int main() { int t; scanf("%d", &t); while (t--) { int n, m, q; scanf("%d%d%d", &n, &m, &q); memset(bit, 0, sizeof(bit)); memset(ans, 0, sizeof(ans)); int x, y; int cnt = 0; for (int i = 1; i <= m; ++i) { scanf("%d%d", &x, &y); a[++cnt] = {0, x, y, 0, realv(index(x, y, n))}; } int x1, y1, x2, y2; for (int i = 1; i <= q; ++i) { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); a[++cnt] = {1, x1 - 1, y1 - 1, i, 0}; a[++cnt] = {-1, x1 - 1, y2, i, 0}; a[++cnt] = {-1, x2, y1 - 1, i, 0}; a[++cnt] = {1, x2, y2, i, 0}; } sort(a + 1, a + 1 + cnt); for (int i = 1; i <= cnt; ++i) { if (a[i].f) ans[a[i].id] += sum(a[i].x) * a[i].f; else update(a[i].x, n, a[i].k); } for (int i = 1; i <= q; ++i) printf("%lld\n", ans[i]); } return 0; }