A. The beautiful values of the palace【2019ICPC南京网络赛】【带修树状数组】

题目

给你一个奇数的n,按照以下图的规律构造矩阵
在这里插入图片描述
在这里插入图片描述
给你m个坐标,每个坐标上都有这些数字,而其他坐标都为0
给你p次询问,每次询问给你一个矩形,求矩形内的数字的数位之和
例如 19 和 25 和 591的数位之和为 10 + 7 + 15 = 32

思路

x = x − n/2 − 1;
y = x − n/2 − 1 t = max(abs(x), abs(y)); //确定该点在第几圈螺旋
if(x >= y)ans = N ∗ N − 4 ∗ t ∗ t − 2 ∗ t − x − y; //在向右与向上的路线上 
else ans = N ∗ N − 4 ∗ t ∗ t + 2 ∗ t + x + y; //在向左与向下的路线上

通过规律可以得出每个坐标的位置
将一个坐标上的值得出来
一个矩形的和可以拆成四个矩形
因此一次询问就可以看出求四次二维前缀和 标记每次询问是加还是减;
将宫殿和询问按 y 坐标排序 维护一个带修树状数组
每加入一个值添加其值
每加入一个询问就求其前缀和

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 5;
struct node1 {
	ll x, y, val;
	node1(ll _x = 0, ll _y = 0, ll _val = 0): x(_x), y(_y), val(_val) {}
	bool operator < (node1 b) {
		return y < b.y;
	}
} point[maxn];
struct node2 {
	ll x, y, id, flag;
	node2(ll _x = 0, ll _y = 0, ll _id = 0, ll _flag = 0): x(_x), y(_y), id(_id), flag(_flag) {}
	bool operator < (node2 b) {
		return y < b.y;
	}
} mar[maxn << 2];
ll n, m, p;
ll cal(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;
	}
	ll sum = 0;
	while(ans) {
		sum += ans % 10;
		ans /= 10;
	}
	return sum;
}
ll lowbit(ll x) {
	return x&(-x);
}
ll bit[maxn << 1];
void add(ll x, ll val) {
	if(x == 0) {
		return;
	}
	while(x < maxn) {
		bit[x] += val;
		x += lowbit(x);
	}
}
ll que(ll x) {
	ll ans = 0;
	while(x) {
		ans += bit[x];
		x -= lowbit(x);
	}
	return ans;
}
ll ans[maxn];
int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		scanf("%lld %lld %lld", &n, &m, &p);
		memset(bit, 0, sizeof(bit));
		memset(ans, 0, sizeof(ans));
		for(int i = 0; i < m; i++) {
			ll x, y;
			scanf("%lld %lld", &x, &y);
			point[i] = node1(x, y, cal(x, y));
		}
		sort(point, point+m);
		ll a, b, c, d;
		for(int i = 0; i < p; i++) {
			scanf("%lld %lld %lld %lld", &a, &b, &c, &d);
			mar[i*4] = node2(a-1, b-1, i, 1);
			mar[i*4+1] = node2(a-1, d, i, -1);
			mar[i*4+2] = node2(c, b-1, i, -1);
			mar[i*4+3] = node2(c, d, i, 1);
		}
		sort(mar, mar+p*4);
		int pos = 0;
		for(int i = 0; i < p*4; i++) {
			while(pos < m && point[pos].y <= mar[i].y) {
				add(point[pos].x, point[pos].val);
				pos++;
			}
			ans[mar[i].id] += que(mar[i].x) * mar[i].flag;
		}
		for(int i = 0; i < p; i++) {
			printf("%lld\n", max(0LL, ans[i]));
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值