题目链接
题意:给你一个螺旋矩阵,再给定m固定的格子,每个格子都有权值,最后有p次询问,每次询问给一个范围,求出这个范围内的给定的格子的权值之和。
思路:先想办法推出公式,根据x, y, n推出这个格子的权值。由于数据量太大,需要离线处理,把这些点存储起来后,按照x的顺序来扫描,如果该点是给定的点,需要插入,利用树状数组来维护前缀和。如果该点是询问前缀和的,读取前缀和即可,此时其他x大于它的点肯定不会被覆盖,而y大于它的点也不会被在前缀里面,非常巧妙的解决了问题。
代码看起来有点长,其实除去求值和树状数组,核心语句就那么几行,弄懂很关键。把不会的题学会,才能进步!
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define lowbit(i) ((i) & (-i))
using namespace std;
typedef long long ll;
const ll MAXN = 1e6+5;
ll n, m, p;
ll ans[MAXN];
struct Node{
ll x, y, id, tag; //tag为2为插入的点,此时id为值。1或-1为询问,id为询问的次序
}node[MAXN];
bool cmp(Node n1, Node n2){
if(n1.x < n2.x) return true;
else if(n1.x == n2.x && n1.tag > n2.tag) return true;
return false;
}
//根据坐标获取值
ll getVal(ll x, ll y, ll n){
x = x-n/2-1;
y = y-n/2-1;
ll t = max(abs(x),abs(y));//第几个螺旋
ll ans;
if(x>=y) ans = n*n-4*t*t-2*t-x-y;
else ans = n*n-4*t*t+2*t+x+y;
return ans;
}
ll getDigit(ll val){
ll res = 0;
while(val > 0){
res += val % 10;
val /= 10;
}
return res;
}
//树状数组
ll c[MAXN];
void update(ll x, ll v){
for(ll i = x; i <= n; i = i+lowbit(i))
c[i] += v;
}
ll getSum(ll x){
ll sum = 0;
for(ll i = x; i > 0; i = i-lowbit(i))
sum += c[i];
return sum;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
memset(ans, 0, sizeof(ans));
memset(c, 0, sizeof(c));
scanf("%lld%lld%lld", &n, &m, &p);
ll x, y;
// 插入的值
for(ll i = 1; i <= m; ++i)
{
scanf("%lld%lld", &x, &y);
node[i].x = x; node[i].y = y;
node[i].id = getDigit(getVal(x, y, n));
node[i].tag = 2;
}
//查询的值
ll cnt = m;
ll x1, y1, x2, y2;
for(ll i = 1; i <= p; ++i)
{
//cin >> x1 >> y1 >> x2 >> y2;
scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
node[++cnt].x = x1-1, node[cnt].y = y1-1, node[cnt].id = i, node[cnt].tag = 1;
node[++cnt].x = x1-1, node[cnt].y = y2, node[cnt].id = i, node[cnt].tag = -1;
node[++cnt].x = x2, node[cnt].y = y2, node[cnt].id = i, node[cnt].tag = 1;
node[++cnt].x = x2, node[cnt].y = y1-1, node[cnt].id = i, node[cnt].tag = -1;
}
sort(node+1, node+1+cnt, cmp);
for(ll i = 1; i <= cnt; ++i)
{
if(node[i].tag == 2){
update(node[i].y, node[i].id);
}
else{
ll res = getSum(node[i].y);
ans[node[i].id] += res * node[i].tag;
}
}
for(ll i = 1; i <= p; ++i)
printf("%lld\n", ans[i]);
}
return 0;
}