旋转差分,以及曼哈顿距离转换切比雪夫距离

在这里插入图片描述

拿到这个问题我们要怎么去想呢,如果是暴力的修改的话,我们的复杂度为 m * 2r*r 的复杂度,这也太暴力了,我们要怎么办呢,我们能不能用差分数组来实现呢?

我们首先要看如何实现公式的转换

在这里插入图片描述

很显然我们可以利用公式实现转换,这也给我们做题提供了新的思路

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

const int N = (int)3e3+5;
int c[N][N];
int n,m;
int main(){
	cin >> n >> m;
	int x,y,r;
	for(int k=1;k<=m;k++){
		cin >> x >> y >> r;
		for(int i=max(1,x-r);i<=min(n,x+r);i++){
			// 一定要处理好边界
			int t = r - abs(x-i);
			c[i][max(1,y-t)]++;
			c[i][min(n+1,y+t+1)]++;  // 这个边界一定要注意,要超出n 
		}
	}
	int ans = 0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			c[i][j] += c[i][j-1];
			if(c[i][j]&1) ans++;
		}
	}
	cout << ans;
	return 0;
}

但是如果m的数据范围变成在这里插入图片描述
我们这个做法是会超时的,那么正确的解法是什么呢
在这里插入图片描述
在这里插入图片描述
但是要注意的是我们这么转换的话,其实会放大我们的图,会出现四个不存在的点,且我们的坐标可能出现负数,故我们也要进行偏移处理

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;

const int N = (int)6005;
int c[N][N];
int n,m;
int main(){
	cin >> n >> m;
	for(int i=1;i<=m;i++){
		int x,y,r;
		cin >> x >> y >> r;
		int nx = x+y, ny = x-y+3000;
		// 接着进行二维差分
		c[max(nx-r,1)][max(ny-r,1)] ^= 1;
		c[min(nx+r+1,6000)][min(ny+r+1,6000)]^=1;
		c[min(nx+r+1,6000)][max(ny-r,1)]^=1;
		c[max(nx-r,1)][min(ny+r+1,6000)]^=1;
	}
	int ans = 0;
	for(int i=1;i<=6000;i++){
		for(int j=1;j<=6000;j++){
			c[i][j] = c[i][j]^c[i-1][j-1]^c[i-1][j]^c[i][j-1];
			int x = (i+j-3000)/2,y = (i-j+3000)/2;
			if(c[i][j]&&(i&1)==(j&1)&&x>0&&x<=n&&y>0&&y<=n)
			ans++;
		}
	}
	cout << ans;
	return 0;
}

有一个细节需要处理,那就是如何知道我们这个点是不是之前存在的呢,通过 (i&1)==(j&1) 就可以判断,二者的奇偶性必须相同

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wniuniu_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值