題目大意:給定平面,多次插入點和圓,每次插入點時詢問當前插入的點是否在之前插入的所有圓中並且至少在乙個圓中
直接用資料結構維護這些點和圓不是很好寫,我們考慮cdq分治
對於每層分治,我們需要對於[mid+1,r]中的每個點求出[l,mid]中是否所有的圓都覆蓋了這個點
設點的座標為(x0,y0),那麼這個點在所有圓內必須滿足對於所有的圓心(x,y),(x-x0)^2+(y-y0)^2<=x^2+y^2,即2*x*x0+2*y*y0>=x0^2+y0^2
我們發現上面的式子是乙個半平面,斜率為-x0/y0,如果所有的圓心都在這個半平面中,那麼這個點就在所有的圓內。
我們可以對所有的圓心做乙個凸包(上下凸包都要做),保證[mid+1,r]部分斜率遞增,然後對於每個點對應的半平面,去凸包上查詢卡到的點
如果這個點在卡到的圓之內 那麼它就在[l,mid]中所有圓之內 反之則不在
然後就正常做好了- - 如果乙個點的y0為正 就在下凸包上查詢 反之則在上凸包上查詢
由於斜率遞增 所以下凸包應該維護乙個佇列,而上凸包則需要維護乙個棧 y0=0的情況要特判
此外注意左側沒有圓的情況- -
#include #include #include #include #include #define m 500500
#define eps 1e-5
#define inf 1e11
using namespace std;
struct point
point(double _,double __):x(_),y(__) {}
};struct query:point
query(int _,double __,double ___):type(_)
bool operator < (const query &q) const
}mempool[m],*q[m],*nq[m];
int n;
bool compare(query* q1,query* q2)
inline double get_slope(const point &p1,const point &p2)
memcpy(q+x,nq+x,sizeof(q[0])*(y-x+1) );
cdq_divide_and_conquer(x,mid);
int top=0,r=0,h=0;
for(i=x;i<=mid;i++)
for(i=mid+1;i<=y;i++)
else
}cdq_divide_and_conquer(mid+1,y);
l1=x;l2=mid+1;
for(i=x;i<=y;i++)
memcpy(q+x,nq+x,sizeof(q[0])*(y-x+1) );
}int main()
sort(q+1,q+n+1,compare);
cdq_divide_and_conquer(1,n);
for(i=1;i<=n;i++)
return 0;
}
bzoj 2961 共點圓 cdq分治
這道題目資料很弱不保證我的程式完全正確qaq。另外這道題目在2013年集訓隊 中有提到。以下是窩的口胡 對於乙個點 x0,y0 和乙個圓心為 x,y 的圓,顯然當 x0 x 2 y0 y 2 x 2 y 2時點在圓內,化簡得到 2y y0 2x x0 x0 2 y0 2,然後可以把2y0除到右邊去,...
BZOJ2961 共點圓 CDQ分治
bzoj 其實就是推一下圓的式子 長成這個樣子 假設要查詢的點是 x,y 某個圓心是 p,q x p 2 y q 2 leq p 2 q 2 變成 fracp frac leq q 那麼乙個點合法就要對所有圓心都滿足上面這個式子 很明顯拿斜率截就好啦 然後cdq維護上下凸包 附 cdq維護凸包過程 ...
BZOJ2961 共點圓 cdq分治 凸包
bzoj傳送門 首先考慮乙個點 x 0,y 0 什麼時候在乙個圓 x 1,y 1,sqrt 內 顯然有 x 12 y 12 geq x 0 x 1 2 y 0 y 1 2 化簡 2x 0x 1 2y 0y 1 geq x 02 y 02 所有含 x 1,y 1 的項挪到同一邊,除掉乙個 2y 0 假...