题意:
两种操作,一种是增加一个圆心为(x,y),半径为y的圆;
另一种是打出一颗击中(x,y)的子弹并要求输出打中的圆的是在第几次操作加入的,同时删除该圆,否则输出-1。
保证任意时刻没有圆交叉。
我们在CF上VP了这场比赛,然而被C题卡成了弟弟,最后我想到这题做法的时候只剩下十几分钟了,时间不够。。。场下补题的时候,找出一些乱七八糟的错误之后终于AC了
思路:
首先要考虑到,对于当前击中的(x0,y0)来说,可能击中的圆的直径一定大于y0,而对于所有直径大于y0的圆来说,要想在不交叉的情况下包含(x0,y0),那么可能的圆只有x0左右两边最接近它的两个圆,因此只需要将直径大于y0的圆中分别从左右最靠近x0的两个圆找到即可。
现在,题目转化成了如何较快的找到这两个圆。
网上有很多博客做法都是线段树,但是我当时没想到如何用线段树维护,反而想到了分块的做法。
首先,将数据全部读入,对所有的x进行离散化; 时间复杂度O(nlogn)
然后,对从1到离散化后的最大值的区间进行分块,每个块维护一个块内最大值,初值全部设为0; 时间复杂度O(n)
再然后,遍历所有操作,当操作为1的时候,将圆的信息(是第几次操作加入的、直径)存入分块的数组中x离散化后的位置,同时更新块内最大值;时间复杂度O(1)
当操作是2的时候,找到击中点x0离散化后的值所在的块,然后向左(向右)枚举块,直到块内最大值大于y0,再在其中找到最接近x0的圆,然后停止寻找。最后判断左右两边找到的圆是否包含了击中点,是的话,输出该圆是在第几次操作加入的,然后把要删除的圆在数组中的y值设为0,同时暴力更新该圆所在块的块内最大值,否则输出-1。时间复杂度O( sqrt(n) )
因此,总的时间复杂度是O(n sqrt(n) )。
代码:
PS:代码写得有点丑,而且写得是找大于等于y0的圆,因为虽然等于y0的圆一定无法包含(x0,y0),但是也可以保证,在它那边没有其他圆可以包含(x0,y0)
#include<bits/stdc++.h>
using namespace std;
#define For(i,a,b) for(int i=a;i<=b;i++)
#define m_p make_pair
#define p_b push_back
const int N=2e5+10;
const int M=505;
const int mod=1e9+7;
int t,n,L[M],R[M],ma[M],c[N],mp[N];
struct node{
int opt,x,y,x1;
}a[N];
struct qaq{
int id,y;
}b[N];
struct Ans{
int id,x,y;
};
vector<int> s;
bool isInC(int x,int y,int xx,int yy){
return (x-xx)*1ll*(x-xx)+(y-yy)*1ll*(y-yy)<y*1ll*y;
}
int main(){
int k=sqrt(N);
For(i,1,k){
L[i]=k*(i-1)+1;
R[i]=i*k;
}
if(R[k]<N){
k++;
L[k]=R[k-1]+1;
R[k]=N-1;
}
For(i,1,k){
For(j,L[i],R[i]){
c[j]=i;
}
}
scanf("%d",&n);
For(i,1,n){
scanf("%d %d %d",&a[i].opt,&a[i].x,&a[i].y);
s.p_b(a[i].x);
}
sort(s.begin(),s.end());
s.end()=unique(s.begin(),s.end());
int pos,l,r,lpos,rpos;
Ans lm,rm;
For(i,1,n){
a[i].x1=lower_bound(s.begin(),s.end(),a[i].x)-s.begin()+1;
mp[a[i].x1]=a[i].x;
}
For(i,1,n){
if(a[i].opt==1){
b[a[i].x1].y=(a[i].y<<1);//存y的两倍
b[a[i].x1].id=i;
if(b[a[i].x1].y>ma[c[a[i].x1]]) ma[c[a[i].x1]]=b[a[i].x1].y;
}
else{
lm.id=rm.id=-1,l=a[i].x1-1,r=a[i].x1+1;
rpos=lpos=c[a[i].x1];
while(lpos>0&&lm.id==-1){
if(ma[lpos]>=a[i].y){
l=min(R[lpos],a[i].x1);
while(l>=L[lpos]&&lm.id==-1){
if(b[l].y>=a[i].y) lm.x=l,lm.y=b[l].y,lm.id=b[l].id;
l--;
}
}
lpos--;
}
while(rpos<=k&&rm.id==-1){
if(ma[rpos]>=a[i].y){
r=max(L[rpos],a[i].x1);
while(r<=R[rpos]&&rm.id==-1){
if(b[r].y>=a[i].y) rm.x=r,rm.y=b[r].y,rm.id=b[r].id;
r++;
}
}
rpos++;
}
if(lm.id!=-1||rm.id!=-1){
if(lm.id!=-1&&isInC(mp[lm.x],lm.y>>1,a[i].x,a[i].y)){
pos=c[lm.x],b[lm.x].y=ma[pos]=0;
For(j,L[pos],R[pos]) if(b[j].y>ma[pos]) ma[pos]=b[j].y;
printf("%d\n",lm.id);
}
else if(rm.id!=-1&&isInC(mp[rm.x],rm.y>>1,a[i].x,a[i].y)){
pos=c[rm.x],b[rm.x].y=ma[pos]=0;
For(j,L[pos],R[pos]) if(b[j].y>ma[pos]) ma[pos]=b[j].y;
printf("%d\n",rm.id);
}
else printf("-1\n");
}
else printf("-1\n");
}
}
return 0;
}