G. Best ACMer Solves the Hardest Problem

Problem - G - Codeforces

G. Best ACMer Solves the Hardest Problem_第1张图片

有一天,一位优秀的ACMer将离开这个领域,面对新的挑战,就像前辈们所做的一样。他们中的一些人接管了家族企业,一些人在失业的边缘挣扎。一些人有勇气展示自己,成为专业的Ingress玩家,一些人仍在不断挑战自己的极限,尝试解决Project Euler中的所有问题。

但是,对于前国王Benecol de Cecco来说,所有这些目的都太肤浅了。他现在所做的就是成为StackOverflow上最好的回答者。StackOverflow是最大、最值得信赖的在线社区,供开发人员学习、分享他们的编程知识和建立他们的职业生涯。

今天,他注意到了一个问题,由Kevin Li发布,说:最近,我实现了一个实验,需要找到所有数据记录,它们到查询点q的欧几里得距离是相同的值r。我尝试使用k-d树来提高搜索效率。然而,我发现k-d树需要遍历所有叶节点才能返回结果,也就是说,它仍然需要比较所有数据集才能获得结果。

这个问题可以形式化地建立一个具有实时查询和修改的数据库。首先,假设我们在平面上有n个不同的点。第i个点位于(xi,yi)处,具有权重wi。然后,我们考虑动态给出的几个查询和修改:

1 x y w,插入一个权重为w的新点(x,y),在操作之前我们保证没有点位于那个位置; 2 x y,删除位于(x,y)处的点,在操作之前我们保证该点存在; 3 x y k w,对于每个到(x,y)的欧几里得距离为k−−√的点,将其权重增加w; 4 x y k,查询所有到(x,y)的欧几里得距离为k−−√的点的权重总和。

Benecol de Cecco说这个问题很容易,他让我与大家分享这个问题。顺便说一下,两个点(x0,y0)和(x1,y1)之间的欧几里得距离等于(x0−x1)2+(y0−y1)2−−−−−−−−−−−−−−−−−−√。

输入 输入包含多个测试用例,第一行包含一个正整数T,表示测试用例的数量,最多为1000。

对于每个测试用例,第一行包含两个整数n和m,表示平面上的初始点数和操作数,其中1≤n,m≤105。

以下每个n行都包含三个整数x、y和w,满足1≤x,y,w≤6000,描述了初始时位于(x,y)处的权重为w的点。

以下每个m行都包含一个查询或修改操作。这些操作采用上述形式给出。为使所有操作中的x和y动态化,我们使用lastans表示最近查询的答案,其初始值为零。对于输入中具有值x和y的每个操作,它们的实际值应为(((x+lastans)mod6000)+1)和(((y+lastans)mod6000)+1)。操作中的所有系数都是整数,满足0≤k≤107和1≤x,y,w≤6000。

我们保证所有测试用例中n和m的总和分别不超过106。

输出 对于每个测试用例,首先输出一行包含“Case #x:”(不带引号),其中x是从1开始的测试用例编号。

然后对于每个查询,在一行中输出一个整数表示答案。

Example

Input

Copy

1
3 6
2999 3000 1
3001 3000 1
3000 2999 1
1 2999 3000 1
4 2999 2999 1
2 2995 2996
3 2995 2995 1 1
4 2995 2995 1
4 3000 3000 1

Output

Copy

Case #1:
4
6
0

Note

In the sample case, if we ignore the special input format for dynamic x

and y

in operations, here we can show these modifications and queries directly in an offline format as follows:

  • 1 3000 3001 1;
  • 4 3000 3000 1;
  • 2 3000 3001;
  • 3 3000 3000 1 1;
  • 4 3000 3000 1;
  • 4 3007 3007 1.

题解:
假设点tx,ty与此时的点x,y的距离为根号k

(tx - x)^2 + (ty - y)^2 = k

设dx = tx - x

dy = ty - y

由于k的大小只有1e7,x,y的大小最多6000

我们可以枚举出来,所有满足k的dx和dy

那么符合条件的

tx = x - dx

ty = y - dy

又因为我们求的dx,dy都是正的,但是他们可能是负的,所以有四种情况

具体细节见代码,

比赛中由re导致的错误情况有很多,大小超int也可能导致

#include
using namespace std;
//#define int long long
const int N=1e7 + 10;
typedef pair PII;
vector p[N];
bool vis[7010][7010];
int res[7010][7010];
int dx[4] = {1,1,-1,-1};
int dy[4] = {1,-1,1,-1};
int idx;
void solve()
{
	long long last = 0;
	int n,q;
	cin >> n >> q;
	vector t; 
	for(int i = 1;i <= n;i++)
	{
		int x,y,w;
		cin >> x >> y >> w;
		t.push_back({x,y});
		vis[x][y] = 1;
		res[x][y] = w;
	}
	cout <<"Case #"<<++idx<<":\n";
	while(q--)
	{
		int op,x,y,k,w;
		cin >> op >> x >> y;
		x = (x + last)%6000 + 1;
		y = (y + last)%6000 + 1;
		t.push_back({x,y});
		
		
		if(op == 1)
		{
			cin >> w;
			vis[x][y] = 1;
			res[x][y] = w;
		}
		else if(op == 2)
		{
			vis[x][y] = 0;
			res[x][y] = 0;
		}
		else if(op == 3)
		{
			cin >> k >> w;
			if(!p[k].size())
			continue;
			set s;
			for(auto [nx,ny]:p[k])
			{
				for(int j = 0;j < 4;j++)
				{
					int tx = x + dx[j]*nx;
					int ty = y + dy[j]*ny;
					if(tx <= 0||tx > 6000||ty <= 0||ty > 6000)
					continue;
					s.insert({tx,ty});
				}
			}	
			
			
			for(auto[tx,ty]:s)
			{
				if(vis[tx][ty])
				res[tx][ty] += w;
			}
			
			
		}
		else
		{
			cin >> k;
			last = 0;
			if(!p[k].size())
			{
				cout < s;
			for(auto [nx,ny]:p[k])
			{
				for(int j = 0;j < 4;j++)
				{
					int tx = x + dx[j]*nx;
					int ty = y + dy[j]*ny;
					if(tx <= 0||tx > 6000||ty <= 0||ty > 6000)
					continue;
					s.insert({tx,ty});
				}
			}			
			
			for(auto[tx,ty]:s)
			{
				if(vis[tx][ty])
				last += res[tx][ty];
			}
			cout << last <<"\n";
		}
	}
	
	for(auto tt:t)
	{
		vis[tt.first][tt.second] = 0;
		res[tt.first][tt.second] = 0;
	}
	t.clear();
}
int main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
	for(int i = 0;i <= 6000;i++)
	{
		for(int j = 0;j <= 6000;j++)
		{
			if(i*i + j*j > 1e7)
			{
				break;
			}
			p[i*i + j*j].push_back({i,j});
		}
	}
	int t = 1;
	cin >> t;
	while(t--)
	{
		solve();
	}
}

你可能感兴趣的:(数学)