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;
}

浙公网安备 33010602011771号