链接:Gym101630 - A Archery Tournament
题意:
共 n n n个操作:
操作1:放置一个圆形靶子,中心在 ( x i , y i ) (x_i,y_i) (xi,yi),其中 y i ≥ 0 y_i\ge 0 yi≥0且靶子一定相切于 x x x轴(即半径 r i = y i r_i=y_i ri=yi),不同靶子之间不会有重叠(可能相切);
操作2:投掷一个飞镖至 ( x j , y j ) (x_j,y_j) (xj,yj),若击中靶子(不包含边界),则输出其编号,并删除该靶子,否则输出“ − 1 -1 −1”。
分析:
由于圆形靶子一定相切于 x x x轴,且不会有重叠,则在直线 x = p x=p x=p上,至多有 log N \log N logN个靶子;
首先,将靶子的左右边界 L i L_i Li、 R i R_i Ri,飞镖的横坐标 X j X_j Xj均离散化,但是如果对于每个 p p p都存入 x = p x=p x=p上的靶子,空间复杂度可以接受,但是每次存入/删除都需改变 R i − L i R_i-L_i Ri−Li个,时间复杂度会达到 O ( N ) O(N) O(N);
考虑利用线段树(主要是线段树的思想),把 每个靶子的左右边界 [ L i , R i ] [L_i,R_i] [Li,Ri]依照线段树划分为 log ( R i − L i ) \log(R_i-L_i) log(Ri−Li)个区间,存入/删除靶子(线段树的每个结点为set/vector),时间复杂度 O ( log N ) O(\log N) O(logN);
查找时,对于 飞镖的横坐标 X j X_j Xj,从根结点一路查找至叶子结点 X j X_j Xj( log N \log N logN),对于每个结点,至多有 l o g N log N logN个靶子要查找,故时间复杂度为 O ( log 2 N ) O(\log^2N) O(log2N)
以下代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=2e6+10;
int n,m,b[maxn];
struct operation
{
int op;
int x,y;
int L,R; //靶子的左右边界
int X; //飞镖的横坐标
}a[maxn];
void pre_work()
{
sort(b+1,b+m+1);
m=unique(b+1,b+m+1)-(b+1);
for(int i=1;i<=n;i++)
{
if(a[i].op==1)
{
a[i].L=lower_bound(b+1,b+m+1,a[i].L)-b;
a[i].R=lower_bound(b+1,b+m+1,a[i].R)-b;
}
else
a[i].X=lower_bound(b+1,b+m+1,a[i].X)-b;
}
}
set<int> s[maxn];
void updata(int rt,int l,int r,int ql,int qr,int op,int tg)
{
if(ql<=l&&r<=qr)
{
if(op==1)
s[rt].insert(tg);
else
s[rt].erase(tg);
return;
}
int mid=(l+r)>>1;
if(ql<=mid)
updata(rt<<1,l,mid,ql,qr,op,tg);
if(qr>mid)
updata(rt<<1|1,mid+1,r,ql,qr,op,tg);
}
bool query(int rt,int l,int r,int pos,int id,int &tg)
{
for(auto it:s[rt])
{
LL x=a[id].x,y=a[id].y,u=a[it].x,v=a[it].y;
if((u-x)*(u-x)+(v-y)*(v-y)<v*v)
{
tg=it;
return true;
}
}
if(l==r)
return false;
int mid=(l+r)>>1;
if(pos<=mid)
return query(rt<<1,l,mid,pos,id,tg);
else
return query(rt<<1|1,mid+1,r,pos,id,tg);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d %d",&a[i].op,&a[i].x,&a[i].y);
if(a[i].op==1)
{
b[++m]=a[i].L=a[i].x-a[i].y;
b[++m]=a[i].R=a[i].x+a[i].y;
}
else
b[++m]=a[i].X=a[i].x;
}
pre_work();
for(int i=1;i<=n;i++)
{
if(a[i].op==1)
updata(1,1,m,a[i].L,a[i].R,1,i);
else
{
int tg;
if(query(1,1,m,a[i].X,i,tg))
{
printf("%d\n",tg);
updata(1,1,m,a[tg].L,a[tg].R,-1,tg);
}
else
printf("-1\n");
}
}
return 0;
}