给出一个
6000
∗
6000
6000*6000
6000∗6000大小的平面,平面上初始的时候有若干个点,点上有权值。然后支持四种操作:1.插入权值为
w
w
w的点。2.删除某个位置的点。3.给距离某个位置为
k
\sqrt k
k距离的点都加上
w
w
w的权值。4.对距离某个位置
k
\sqrt k
k距离的点权求和。
点的范围不大。可以预处理出来所有距离为
k
\sqrt k
k在两个方向上可以分解为哪些长度。插入和删除用map暴力实现,对于修改和求和,用set去重,然后暴力修改求和。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int tot=1e7;
#define MP make_pair
#define PII pair<int,int>
map<PII,int> mp;
set<PII> s;
vector<PII> v[tot+1];
void init() {
for(int i=0;i<=6000;i++) {
for(int j=0;j<=6000;j++) {
if(i*i+j*j<=tot) v[i*i+j*j].push_back(MP(i,j));
else break;
}
}
}
int Dx[4]={1,1,-1,-1};
int Dy[4]={1,-1,1,-1};
bool check(int x,int y) {
if(x>=1&&x<=6000&&y>=1&&y<=6000) return 1;
else return 0;
}
int main() {
init();
int T;
scanf("%d",&T);
int kase=0;
while(T--) {
printf("Case #%d:\n",++kase);
mp.clear();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
mp[MP(x,y)]=w;
}
ll lastans=0;
while(m--) {
int opt,x,y,k,w;
scanf("%d%d%d",&opt,&x,&y);
x=(x+lastans)%6000+1;
y=(y+lastans)%6000+1;
if(opt==1) {
scanf("%d",&w);
mp[MP(x,y)]=w;
}
if(opt==2) {
mp.erase(MP(x,y));
}
if(opt==3) {
s.clear();
scanf("%d%d",&k,&w);
for(auto &p:v[k]) {
int dx=p.first;
int dy=p.second;
for(int i=0;i<4;i++) {
int nx=x+dx*Dx[i];
int ny=y+dy*Dy[i];
if(s.find(MP(nx,ny))!=s.end()) continue;
s.insert(MP(nx,ny));
if(check(nx,ny)) {
if(mp.count(MP(nx,ny))) {
mp[MP(nx,ny)]+=w;
}
}
}
}
}
if(opt==4) {
s.clear();
scanf("%d",&k);
ll sum=0;
for(auto &p:v[k]) {
int dx=p.first;
int dy=p.second;
for(int i=0;i<4;i++) {
int nx=x+dx*Dx[i];
int ny=y+dy*Dy[i];
if(s.find(MP(nx,ny))!=s.end()) continue;
s.insert(MP(nx,ny));
if(check(nx,ny)) {
if(mp.count(MP(nx,ny))) {
sum+=mp[MP(nx,ny)];
}
}
}
}
printf("%lld\n",sum);
lastans=sum;
}
}
}
return 0;
}