题意:
有n*n的矩阵,值从右上开始一圈一圈往里面递增。(1,1)在左下,(n,n)在右上。
给出m个宫殿,每个宫殿有一个美丽值,美丽值为矩阵所在位置上的值的数位和,如18=1 + 8 = 9
给出q个询问,每个询问是一个矩阵,求在矩阵内的宫殿美丽值的和。
思路:
求在矩阵上的值找了个螺旋矩阵的模板。在知道了每个宫殿的美丽值之后,如何快速地解决问题。首先需要离线做,记录所有的询问。询问也是一个矩阵,那么就可以用二维前缀的形式,二维的话空间可能不太行,那么就需要优化成一维。把询问拆点,每个询问变成4个点分别是(x-1,y-1,1),(x-1,y,-1),(x,y-1,-1),(x,y,1),1和-1表示符号,然后把这些拆出来的点和宫殿一起按照x、y排序,这样x是递增的,只需要维护y轴方向的前缀和就好了。
参考代码:
#include <bits/stdc++.h>
#define _debug(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
const int M = 1e5+5;
struct node2 {
ll x, y, val, tp, id, fh;//tp(true:询问,false:宫殿),fh(询问拆点的符号)
node2() {}
node2(ll x, ll y, ll id, ll fh) {
this->x = x;
this->y = y;
this->tp = 1;
this->id = id;
this->fh = fh;
}
bool operator<(const node2 &a) const {
if (x == a.x && y == a.y)return tp < a.tp;//同坐标时宫殿优先
if (x == a.x)return y < a.y;
return x < a.x;
}
} po[M * 5];
ll n, m, q;
ll real_val(ll x) {
ll ret = 0;
while (x) {
ret += x % 10;
x /= 10;
}
return ret;
}
ll get_val(ll x, ll y, ll n){
ll qs = n / 2, q = min(n - y + 1, min(n - x + 1, min(x, y))) - 1;
if (x == qs + 1 && y == qs + 1) return n * n;
ll ans = 1ll * q * (8 * qs + 8 * (qs - q + 1)) / 2;
if (n - x == q) ans += n - q - y + 1;
else if (y - 1 == q) ans += n - 2 * q + 1 + n - q - 1 - x;
else if (x - 1 == q) ans += n - 2 * q + 1 + n - 2 * q - 2 + y - q - 1;
else ans += n - 2 * q + 1 + n - 2 * q - 2 + n - 2 * q - 1 + x - q - 1;
return ans;
}
ll tree[N];
ll ans[M];
int lowbit(int x){
return x&(-x);
}
void update(int x,int ed,ll val){
if(x<1)return;
for(;x<ed;x+=lowbit(x)){
tree[x]+=val;
}
}
ll query(int x){
ll ret=0;
for(;x>0;x-=lowbit(x)){
ret+=tree[x];
}
return ret;
}
void solve() {
for (ll i = 1; i <= m; i++) {
scanf("%lld%lld", &po[i].x, &po[i].y);
po[i].val = real_val(get_val(po[i].x, po[i].y,n));
po[i].tp=0;
}
ll top = m;
ll x1, y1, x2, y2;
for (ll i = 1; i <= q; i++) {//询问拆点
scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
po[++top] = node2(x1 - 1, y1 - 1, i, 1);
po[++top] = node2(x2, y2, i, 1);
po[++top] = node2(x1 - 1, y2, i, -1);
po[++top] = node2(x2, y1 - 1, i, -1);
}
sort(po + 1, po + 1 + top);
memset(tree,0, sizeof(tree));
memset(ans, 0, sizeof(ans));
for (ll i = 1; i <= top; i++) {
if (po[i].tp) {
ans[po[i].id] += po[i].fh * query(po[i].y);
} else {
update(po[i].y,N, po[i].val);
}
}
for (ll i = 1; i <= q; i++) {
printf("%lld\n", ans[i]);
}
}
int main() {
ll t;
scanf("%lld", &t);
for (ll ca = 1; ca <= t; ca++) {
scanf("%lld%lld%lld", &n, &m, &q);
solve();
}
return 0;
}