题意:
给你一个宽度为奇数的正方形,每个块都有一定的权值,把权值的每一位加起来得到每一个块的“美丽值”。现在告诉你正方形中有一些块上面建造的有宫殿,然后问你在某一个矩形区域内所有宫殿的“美丽值”的总和。
在网上看了别人的解答,在此记录
(注意,一个函数的返回值是 ll (long long) 的话或者内部需要使用 ll ,这个函数内部就不应该出现int,否则可能出现隐式越界,难以察觉)
题目有两个难点
第一 要在O(1)的时间内算出螺旋矩阵的值,
螺旋矩阵可以分圈算,因为每圈的数字的数量是一个等差数列。
第一步,算出要求的点所在的圈数,
ll q = min(min(x, y), min(n - x + 1, n - y + 1));
第二步,算出它是圈里面的第几个数(同一圈里面的数单调递增),
if (x == y && y == q)
num = 1;
else if (y > x)
num = x + y - 2 * q + 1;
else
num = 4 * (n - 2 * q + 1) - (x + y - 2 * q) + 1;
第三步,算出他所在的圈的第一个元素的值(每圈的元素的数量为等差数列,用求和公式可以算出),在加上刚刚算出的num,就是元素的值。
ll get(ll x, ll y, ll n) {//get(n-x+1, n-y+1,n)
int q = min(min(x, y), min(n - x + 1, n - y + 1));
ll num;
if (x == y && y == q)
num = 1;
else if (y > x)
num = x + y - 2 * q + 1;
else
num = 4 * (n - 2 * q + 1) - (x + y - 2 * q) + 1;
return num+2 * ((n - 1) + (n - 2 * (q - 1) + 1))*(q - 1);
}
第二个难点在于在O(1)或者O(lgn)的时间内求出一个区间的值之和,用二维的树状数组可以很好的解决问题,但是这样空间不允许。有个好办法就是用前缀和加线段树,
所以只需要求出A B C D就可以求出M。具体方法可以把M保存为ABCD四个顶点的坐标(ABCD的右下角坐标),把可用的点的坐标也保存进来,把这些数据按照X轴排序,同时想到到y坐标的,所以遇到点就加入树状数组,遇到区间就用树状数组求和。因为是按照x后排序的,所以可以保证x和y都慢猪条件(要求的区间是从(0,0)开始的)。
代码如下
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>
#include <stack>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define l(x) ((x)<<1)
#define r(x) ((x)<<1|1)
#define lowbit(x) ((x)&(-(x)))
#define abs(x) ((x)>=0?(x):(-(x)))
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
struct node {
ll x, y;
ll flag, pos, val;
node(ll xx,ll yy,ll ff,ll pp,ll vv):x(xx),y(yy),flag(ff),pos(pp),val(vv){}
node():node(0,0,0,0,0){}
friend bool operator<(const node & a,const node&t) {
if (a.x != t.x) return a.x < t.x;
if (a.y != t.y)return a.y < t.y;
return a.pos < t.pos;
}
};
int m, n,p,len;
ll bit[1000005*2];
node a[1000005*2];
ll ans[1000005];
ll sum(ll i) {
ll s = 0;
while (i > 0) {
s += bit[i];
i -= lowbit(i);
}
return s;
}
void add(ll i, ll x) {
while (i <= n) {
bit[i] += x;
i += lowbit(i);
}
}
ll get(ll x, ll y, ll n) {//get(n-x+1, n-y+1,n)
int q = min(min(x, y), min(n - x + 1, n - y + 1));
ll num;
if (x == y && y == q)
num = 1;
else if (y > x)
num = x + y - 2 * q + 1;
else
num = 4 * (n - 2 * q + 1) - (x + y - 2 * q) + 1;
return num+2 * ((n - 1) + (n - 2 * (q - 1) + 1))*(q - 1);
}
void init() {
ms(bit, 0);
ms(ans, 0);
len = 0;
}
void solve() {
scanf("%d%d%d", &n, &m, &p);
ll x, y;
ll tt,temp;
for (int i = 0; i < m; i++) {
scanf("%lld%lld", &x, &y);
tt = get(n-x+1, n-y+1, n);
temp = 0;
while (tt) {
temp += tt % 10;
tt /= 10;
}
a[len++] = node(x, y, 0, i, temp);
}
ll x1, y1, x2, y2;
for (int i = m; i <= m + p-1; i++) {
scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
a[len++] = node(x1 - 1, y1 - 1, 1, i, 0);
a[len++] = node(x2, y1 - 1, -1, i, 0);
a[len++] = node(x1 - 1, y2, -1, i, 0);
a[len++] = node(x2, y2, 1, i, 0);
}
sort(a, a + len);
for (int i = 0; i < len; i++)
if (a[i].pos < m)
add(a[i].y, a[i].val);
else
ans[a[i].pos - m] += sum(a[i].y)*a[i].flag;
for (int i = 0; i < p; i++)
printf("%lld\n", ans[i]);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
init();
solve();
}
return 0;
}