题意:
给定一个
n
∗
n
n*n
n∗n的螺旋矩阵,给
m
m
m个点,使这个矩阵里只有这
m
m
m个点的值是他们的值,别的值都是0。给
q
q
q个询问,每次给一个矩阵,求矩阵里数字之和。
思路:
求出这
m
m
m个点的值,然后对
y
y
y坐标离散化,然后对
x
x
x从小到大排序,按
x
x
x的大小插入主席树,主席树记录的是前缀和,由于主席树每个节点都是一颗线段树,所以可以在查询区间大小时,只要查询离散化后的
l
x
lx
lx到
r
x
rx
rx间的线段树
l
y
ly
ly到
r
y
ry
ry的区间和就是答案了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
int t, n, m, p, root[N], cnt;
int x1, x2, yz1, yz2;
vector<int> vx, vy;
struct nod {
int x, y, w;
bool operator<(const nod &a)const {
return x < a.x;
}
} no[N];
struct node {
int l, r;
ll sum;
} zxs[N * 40];
ll getn(ll x, ll y) {
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 cal(ll x) {
ll sum = 0;
while (x)
sum += x % 10, x /= 10;
return sum;
}
void add(int l, int r, int pre, int &now, int pos, ll num) {
zxs[++cnt] = zxs[pre], now = cnt, zxs[cnt].sum += num;
if(l == r)
return;
int m = (l + r) >> 1;
if(pos <= m)
add(l, m, zxs[pre].l, zxs[now].l, pos, num);
else
add(m + 1, r, zxs[pre].r, zxs[now].r, pos, num);
}
ll query(int pl, int pr, int l, int r, int L, int R) {
if(pl <= l && r <= pr)
return zxs[R].sum - zxs[L].sum;
ll m = (l + r) >> 1, ans = 0;
if(pl <= m)
ans += query(pl, pr, l, m, zxs[L].l, zxs[R].l);
if(pr > m)
ans += query(pl, pr, m + 1, r, zxs[L].r, zxs[R].r);
return ans;
}
int main() {
scanf("%d", &t);
while(t--) {
cnt = 0;
memset(root, 0, sizeof root);
scanf("%d%d%d", &n, &m, &p);
vx.clear(), vy.clear();
for(int i = 1; i <= m; i++) {
scanf("%d%d", &no[i].x, &no[i].y);
no[i].w = cal(getn(no[i].x, no[i].y));
vx.push_back(no[i].x), vy.push_back(no[i].y);
}
sort(no + 1, no + m + 1);
sort(vx.begin(), vx.end());//vx不能erase,因为下面二分查询的是vx的位置,erase后位置少了就不准了。
sort(vy.begin(), vy.end()), vy.erase(unique(vy.begin(), vy.end()), vy.end());
int sz = vy.size();
for(int i = 1; i <= m; i++) {
int ny = lower_bound(vy.begin(), vy.end(), no[i].y) - vy.begin() + 1;
add(1, sz, root[i - 1], root[i], ny, no[i].w);
}
while(p--) {
//由于y坐标离散化的是他们的值,所以相同值离散化后是一样的
scanf("%d%d%d%d", &x1, &yz1, &x2, &yz2);//下面二分的是位置,lx,ly要用lower_bound计算离散化后的位置
int lx = lower_bound(vx.begin(), vx.end(), x1) - vx.begin() + 1;
int ly = lower_bound(vy.begin(), vy.end(), yz1) - vy.begin() + 1;
//这里用upper_bound是为了查找下一个位置,防止和lx相同
int rx = upper_bound(vx.begin(), vx.end(), x2) - vx.begin();
//这里的upper_bound也是查找下一个位置,和x一样,但不能用
//lower_bound(vy.begin(), vy.end(), no[i].y) - vy.begin() + 1;
//因为如果这样的话,当yz2恰好是一个没有点在上面的坐标,所以要找离它最近的而且比它小的坐标,
//若比它大,则多计算了就
int ry = upper_bound(vy.begin(), vy.end(), yz2) - vy.begin();
printf("%lld\n", query(ly, ry, 1, sz, root[lx - 1], root[rx]));
}
}
return 0;
}