[2018ICPC沈阳] G Best ACMer Solves the Hardest Problem map+set

本文介绍了一种处理6000x6000大小平面上点的操作算法,包括点的插入、删除、权值修改及求和。通过预处理所有可能的距离组合,使用map和set进行高效操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出一个 6000 ∗ 6000 6000*6000 60006000大小的平面,平面上初始的时候有若干个点,点上有权值。然后支持四种操作: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值