1. 程式人生 > >【bzoj5173】[Jsoi2014]矩形並 掃描線+二維樹狀數組區間修改區間查詢

【bzoj5173】[Jsoi2014]矩形並 掃描線+二維樹狀數組區間修改區間查詢

scan str div 現在 復雜 需要 truct 一行 include

題目描述

JYY有N個平面坐標系中的矩形。每一個矩形的底邊都平行於X軸,側邊平行於Y軸。第i個矩形的左下角坐標為(Xi,Yi),底邊長為Ai,側邊長為Bi。現在JYY打算從這N個矩形中,隨機選出兩個不同的矩形,並計算它們的並的大小。JYY想知道,交的大小的期望是多少。換句話說即求在所有可能的選擇中,兩個矩形交的面積的平均大小是多大。

輸入

輸入一行包含一個正整數N。 接下來N行,每行4個整數,分別為Xi,Yi,Ai,Bi 2 < = N < = 2*10^5, 0 < = Xi, Yi, Ai, Bi < = 10^6。

輸出

輸出一行包含一個實數,表示矩形並的大小的期望。

樣例輸入

4
0 0 3 5
2 1 3 5
3 3 3 5
0 5 3 5

樣例輸出

1.833333333


題解

掃描線+二維樹狀數組區間修改區間查詢

顯然題目相當於:先給每個矩形內的權值+1,再查詢每個矩形內的權值和即為任意選出兩個矩形(可以相同,有順序)的交面積的和,再減去每個矩形的面積(自己和自己)即得選出兩個不同矩形的交面積之和。

那麽我們把修改和詢問差分成4個端點,就相當於統計每個詢問拆出點的左下修改拆出點的貢獻。使用掃描線維護。

註意到我們要做的是矩形加、矩形求和,可以使用 二維樹狀數組的區間修改區間查詢 的方法,掃描線、一維樹狀數組方法類似。

最後除以 $n(n-1)$ 即可得到答案。

然而本題最惡心一點:本題爆long long!因此只能使用long double大法。由於最終答案只有 $10^{12}$ 級別,因此long double的精度是夠的,不需要擔心精度問題。

時間復雜度 $O(n\log n)$

拿了一血真是開心 ^_^

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
using namespace std;
typedef long double ld;
int k;
struct bit
{
	ld f[N << 2];
	inline void add(int x , ld a)
	{
		int i;
		for(i = x ; i <= k ; i += i & -i) f[i] += a;
	}
	inline ld ask(int x)
	{
		int i;
		ld ans = 0;
		for(i = x ; i ; i -= i & -i) ans += f[i];
		return ans;
	}
}A , B , C , D;
struct data
{
	ld x;
	int y , z , val;
	bool operator<(const data &a)const {return x < a.x;}
}a[N << 1] , b[N << 1];
ld v[N << 2];
inline void modify(ld x , int y , int a)
{
	A.add(y , a) , B.add(y , x * a) , C.add(y , v[y] * a) , D.add(y , x * v[y] * a);
}
inline ld query(ld x , int y)
{
	return (x + 1) * (v[y] + 1) * A.ask(y) - (v[y] + 1) * B.ask(y) - (x + 1) * C.ask(y) + D.ask(y);
}
int main()
{
	int n , i , p = 1;
	ld xi , yi , ai , bi , ans = 0 , sum;
	scanf("%d" , &n) , sum = (ld)n * (n - 1);
	for(i = 1 ; i <= n ; i ++ )
	{
		scanf("%Lf%Lf%Lf%Lf" , &xi , &yi , &ai , &bi) , ans -= ai * bi;
		a[i].x = xi , a[i].y = yi , a[i].z = yi + bi , a[i].val = 1;
		b[i].x = xi - 1 , b[i].y = yi - 1 , b[i].z = yi + bi - 1 , b[i].val = -1;
		a[i + n].x = xi + ai , a[i + n].y = yi , a[i + n].z = yi + bi , a[i + n].val = -1;
		b[i + n].x = xi + ai - 1 , b[i + n].y = yi - 1 , b[i + n].z = yi + bi - 1 , b[i + n].val = 1;
		v[++k] = yi , v[++k] = yi + bi , v[++k] = yi - 1 , v[++k] = yi + bi - 1;
	}
	sort(v + 1 , v + k + 1) , k = unique(v + 1 , v + k + 1) - v;
	for(i = 1 ; i <= 2 * n ; i ++ )
	{
		a[i].y = lower_bound(v + 1 , v + k + 1 , a[i].y) - v;
		a[i].z = lower_bound(v + 1 , v + k + 1 , a[i].z) - v;
		b[i].y = lower_bound(v + 1 , v + k + 1 , b[i].y) - v;
		b[i].z = lower_bound(v + 1 , v + k + 1 , b[i].z) - v;
	}
	sort(a + 1 , a + 2 * n + 1) , sort(b + 1 , b + 2 * n + 1);
	for(i = 1 ; i <= 2 * n ; i ++ )
	{
		while(p <= 2 * n && a[p].x <= b[i].x) modify(a[p].x , a[p].y , a[p].val) , modify(a[p].x , a[p].z , -a[p].val) , p ++ ;
		ans += b[i].val * (query(b[i].x , b[i].z) - query(b[i].x , b[i].y));
	}
	printf("%.9Lf\n" , ans / sum);
	return 0;
}

【bzoj5173】[Jsoi2014]矩形並 掃描線+二維樹狀數組區間修改區間查詢