Problem - G - Codeforces
有一天,一位优秀的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:
题解:
假设点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();
}
}