1. 程式人生 > >【bzoj5183】[Baltic2016]Park 離線+對偶圖+並查集

【bzoj5183】[Baltic2016]Park 離線+對偶圖+並查集

移動 維護 sca 2個 %d 一行 else if {} clu

題目描述

在Byteland的首都,有一個矩形圍欄圍起來的公園。在這個公園裏樹和訪客都以一個圓形表示。公園有四個出入口,每個角落一個(1=左下角,2=右下角,3=右上角,4=左上角)。訪客能通過這些出入口進出公園。訪客在同時碰到一個角落的兩條邊時就可以通過該角落進出公園。訪客在公園裏可以自由地移動,但他們不能和樹和圍欄相交。對於每個訪客,給定他們進入公園的出入口,你的任務是計算他們能在哪個出入口離開公園。

輸入

輸入的第一行包含兩個整數:n,m:樹的數量和訪客的數量。 第二行包含兩個整數:w,h:公園的寬和高。左下角的坐標是(0,0),右上角的坐標是(w,h)。 接下來的n行描述每棵樹。 每行包含3個整數:x,y,r:樹的圓心是(x,y),半徑是r。每棵樹都不會和其他樹和圍欄相交。 最後m行描述每個訪客。每行包含2個整數:r,e:訪客的半徑和他們進入公園的出入口。 數據保證沒有一棵樹會和每個角落的2k*2k的方形區域相交,k是最大的訪客半徑。 1<=N<=2000 1<=M<=100000 4k<w,h<=10^9

輸出

對於每個訪客你要輸出一行,包含了他們能在哪些出入口離開公園,以從小到大的順序輸出,不需要空格分隔。

樣例輸入

5 3
16 11
11 8 1
6 10 1
7 3 2
10 4 1
15 5 1
1 1
2 2
2 1

樣例輸出

1234
2
14


題解

離線+對偶圖+並查集

套路:如果兩棵樹或樹與邊界之間無法通過,則視作它們之間連了一條邊。

那麽左下角能到右下角等價於:下邊界與左、上、右邊界都不連通。其余同理。

然而每個人的半徑都不同,對每個人單獨處理必T無疑。考慮離線,將人按照半徑、樹與樹和樹與邊界按照能通過的最大距離從小到大排序然後處理即可。

連通性可以直接使用並查集維護。

時間復雜度 $O(n^2\log n+m\log m+m\times 常數)$

#include <cmath>
#include <cstdio>
#include <algorithm>
#define squ(x) (x) * (x)
using namespace std;
struct data
{
	double d;
	int x , y;
	data() {}
	data(double a , int b , int c) {d = a , x = b , y = c;}
	bool operator<(const data &a)const {return d < a.d;}
}a[2007010] , q[100010];
double px[2010] , py[2010] , pr[2010];
int f[2010] , ans[100010] , tot;
int find(int x)
{
	return x == f[x] ? x : f[x] = find(f[x]);
}
int main()
{
	int n , m , i , j , p = 1 , t1 , t2 , t3 , t4;
	double w , h;
	scanf("%d%d%lf%lf" , &n , &m , &w , &h);
	for(i = 1 ; i <= n ; i ++ )
	{
		scanf("%lf%lf%lf" , &px[i] , &py[i] , &pr[i]);
		a[++tot] = data(px[i] - pr[i] , i , n + 1);
		a[++tot] = data(py[i] - pr[i] , i , n + 2);
		a[++tot] = data(w - px[i] - pr[i] , i , n + 3);
		a[++tot] = data(h - py[i] - pr[i] , i , n + 4);
		for(j = 1 ; j < i ; j ++ ) a[++tot] = data(sqrt(squ(px[i] - px[j]) + squ(py[i] - py[j])) - pr[i] - pr[j] , i , j);
	}
	for(i = 1 ; i <= m ; i ++ ) scanf("%lf%d" , &q[i].d , &q[i].x) , q[i].d *= 2 , q[i].y = i;
	sort(a + 1 , a + tot + 1) , sort(q + 1 , q + m + 1);
	for(i = 1 ; i <= n + 4 ; i ++ ) f[i] = i;
	for(i = 1 ; i <= m ; i ++ )
	{
		while(p <= tot && a[p].d < q[i].d) f[find(a[p].x)] = find(a[p].y) , p ++ ;
		t1 = find(n + 1);
		t2 = find(n + 2);
		t3 = find(n + 3);
		t4 = find(n + 4);
		if(q[i].x == 1)
		{
			ans[q[i].y] |= (1 << 1);
			if(t2 != t1 && t2 != t3 && t2 != t4) ans[q[i].y] |= (1 << 2);
			if(t1 != t2 && t1 != t3 && t2 != t4 && t3 != t4) ans[q[i].y] |= (1 << 3);
			if(t1 != t2 && t1 != t3 && t1 != t4) ans[q[i].y] |= (1 << 4);
		}
		else if(q[i].x == 2)
		{
			ans[q[i].y] |= (1 << 2);
			if(t2 != t1 && t2 != t3 && t2 != t4) ans[q[i].y] |= (1 << 1);
			if(t3 != t1 && t3 != t2 && t3 != t4) ans[q[i].y] |= (1 << 3);
			if(t1 != t3 && t1 != t4 && t2 != t3 && t2 != t4) ans[q[i].y] |= (1 << 4);
		}
		else if(q[i].x == 3)
		{
			ans[q[i].y] |= (1 << 3);
			if(t1 != t2 && t1 != t3 && t2 != t4 && t3 != t4) ans[q[i].y] |= (1 << 1);
			if(t3 != t1 && t3 != t2 && t3 != t4) ans[q[i].y] |= (1 << 2);
			if(t4 != t1 && t4 != t2 && t4 != t3) ans[q[i].y] |= (1 << 4);
		}
		else
		{
			ans[q[i].y] |= (1 << 4);
			if(t1 != t2 && t1 != t3 && t1 != t4) ans[q[i].y] |= (1 << 1);
			if(t1 != t3 && t1 != t4 && t2 != t3 && t2 != t4) ans[q[i].y] |= (1 << 2);
			if(t4 != t1 && t4 != t2 && t4 != t3) ans[q[i].y] |= (1 << 3);
		}
	}
	for(i = 1 ; i <= m ; i ++ )
	{
		for(j = 1 ; j <= 4 ; j ++ )
			if(ans[i] & (1 << j))
				printf("%d" , j);
		puts("");
	}
	return 0;
}

【bzoj5183】[Baltic2016]Park 離線+對偶圖+並查集