P4631 [APIO2018] 选圆圈
LimpidSlirm · · 个人记录
题意
给定平面上
Solution
显然地,有
稍微剪一下枝,比如维护每个圆的最左端点和最右端点的坐标,然后对于当前圆的左右端点,在数轴上直接二分出区间然后暴力判断是否可以删去即可,时间复杂度
code
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int res=0,flag=1;
char ch=getchar();
while(!('0'<=ch&&ch<='9')) (ch=='-')?flag=-1:1,ch=getchar();
while(('0'<=ch&&ch<='9')) res=res*10+ch-'0',ch=getchar();
return res*flag;
}
struct circle
{
int x,y,r;
};
struct circle data[300010];
int n;
int ans[300010];
pair<int,int> pos[600010],cir[300010];
long long square(int val)
{
return val*1ll*val;
}
bool check(int a,int b)
{
return square(data[a].x-data[b].x)+square(data[a].y-data[b].y)<=square(data[a].r+data[b].r);
}
void solve(int l,int r,int id)
{
for(int i=lower_bound(pos+1,pos+2*n+1,make_pair(l,0))-pos;i<=2*n&&pos[i].first<=r;i++)
{
if(ans[pos[i].second]!=0)
continue;
if(check(id,pos[i].second)==true)
ans[pos[i].second]=id;
}
return ;
}
int main(int argc,const char *argv[])
{
n=read();
for(int i=1;i<=n;i++)
{
data[i].x=read(),data[i].y=read();
data[i].r=read();
cir[i]=make_pair(data[i].r,i);
pos[(i<<1)-1]=make_pair(data[i].x-data[i].r,i);
pos[i<<1]=make_pair(data[i].x+data[i].r,i);
}
std::sort(cir+1,cir+n+1,[](pair<int,int> a,pair<int,int> b){return (a.first==b.first)?a.second<b.second:a.first>b.first;});
std::sort(pos+1,pos+2*n+1);
for(int i=1;i<=n;i++)
{
int id=cir[i].second;
if(ans[id]!=0)
continue;
solve(data[id].x-data[id].r,data[id].x+data[id].r,id);
}
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}