BZOJ2961 共點圓 cdq分治 凸包

2022-03-07 04:48:14 字數 1512 閱讀 6898

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$(假設它是正的),得到:

$y_1\geq -\fracx_1+\frac$

如果是負的:

$y_1\leq -\fracx_1+\frac$

duang!半平面來了

那麼現在的詢問變成了:給定乙個半平面,問是不是所有的點都在這個半平面的上方(或者下方)

顯然,我們如果維護了所有輸入節點的上下凸包,這個問題就迎刃而解了

眾所周知,維護動態上下凸殼可以用$set$或者平衡樹做到$o(n\log n)$

然而博主並不想寫這種東西

所以他寫了非常沙雕的cdq分治23333

分治開始之前先按照所有詢問點的斜率排個序(非詢問點不管)

我們對時間順序分治

進入分治後,首先分治左區間,返回按照橫座標排好序的左區間所有點

求出左區間中所有非詢問的點的上下凸殼

然後對右邊的所有詢問,因為一開始排好序了,所以直接在凸殼上順次雙指標過去

注意:$y_0 > 0$的時候所有點在直線上方,用的是下凸包,反之亦然

最後分治右區間,按照x座標歸併排序,合併左右區間

就是個很模板的cdq斜率分治

#include#include#include#include#include#include#define sqr(x) ((x)*(x))

#define eps 1e-10

#define ll long long

using namespace std;

inline int read()

while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();

return re*flag;

}struct node

memcpy(a+l,tmp+l,sizeof(node)*(r-l+1));

solve(l,mid);

top1=top2=0;

for(i=l;i<=mid;i++)

t1=t2=1;

for(i=mid+1;i<=r;i++)

else

} solve(mid+1,r);

t1=l;t2=mid+1;

for(i=l;i<=r;i++)

memcpy(a+l,tmp+l,sizeof(node)*(r-l+1));

}int main()

else flag=1;

} sort(a+1,a+n+1,cmp);

solve(1,n);

for(i=1;i<=cntq;i++) puts(ans[i]?"yes":"no");

}

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維護凸包過程 ...

BZOJ 2961 共點圓 CDQ分治 凸包

題目大意 給定平面,多次插入點和圓,每次插入點時詢問當前插入的點是否在之前插入的所有圓中並且至少在乙個圓中 直接用資料結構維護這些點和圓不是很好寫,我們考慮cdq分治 對於每層分治,我們需要對於 mid 1,r 中的每個點求出 l,mid 中是否所有的圓都覆蓋了這個點 設點的座標為 x0,y0 那麼...