在平面上有兩兩不相交的\(n\)個圓,即其關係只有相離和包含。求這些圓的異或面積並。
異或面積並為:當一片區域被奇數個圓包含則計算其面積,否則不計算。
輸出所有圓的異或面積並除以\(\pi\)的結果。
\(n\le 200000\)。
前置知識:掃瞄線,set。
可以發現,由於圓是不相交的,那麼這種包含關係可以看作是一棵森林(許多有根樹構成的圖)。
比如像這個幾個圓
可以變成
設每個根的深度為1,那麼深度為奇數的節點的面積是需要加上的,深度為偶數的節點的面積是需要減去的。
即\[ans=\sum_^nr_i^2\times(-1)^
\]同掃瞄線的思想,我們模擬出有一條垂直於\(x\)軸的直線從左向右移動。
查詢剛剛插入的圓的上半圓的前驅(在set中的所有半圓中,在當前圓下方最近的半圓)。如果它的前驅是乙個上半圓,那麼當前圓的深度等於其前驅的深度;若前驅是乙個下半圓,那麼說明當前圓被其前驅所包含,深度為前驅的深度+1。
因為set中要插入同一id的兩個半圓,那麼只要用up表示當前圓是上半圓還是下半圓即可。過載運算子時,可以比較當前掃瞄線與半圓的交點,也可以以圓心的縱座標為第一關鍵字,以上/下半圓為第二關鍵字進行比較。
注意,如果是以掃瞄線與半圓的交點進行比較的話,在掃瞄線進入/離開乙個圓的時候,掃瞄線與兩個半圓的交點會重合。需要在比較函式中將上半圓的交點縱座標加上乙個\(eps\)即可。
我的排序方法是比較當前半圓和掃瞄線的交點。
#include#include#include#include#include#include#include#include#include#include#define il inline
#define re register
#define ll long long
#define ull unsigned long long
#ifdef th
#define debug printf("now is %d\n",__line__);
#else
#define debug
#endif
using namespace std;
templateinline void read(t&x)
x*=fu;
}inline ll read()
return x*fu;
}int g[55];
templateinline void write(t x)
while(x);
for(int i=g;i>=1;--i)putchar('0'+g[i]);putchar('\n');
}#define n 200010
int n,nowx;
ll x[n],y[n],r[n];
struct opt
il bool operator
double calc()const
il bool operator
sort(opt.begin(),opt.end());
ll ans=0;
for(int i=0;iup)
else
}s.insert(o(opt[i].x,0));
if(dep[opt[i].x]) ans+=r[opt[i].x]*r[opt[i].x];
else ans-=r[opt[i].x]*r[opt[i].x];
} else
}write(ans);
return 0;
}
掃瞄線是一種重要的思想。在其應用的過程中常常需要用到set,線段樹等資料結構進行維護。 洛谷P3261 JLOI2015 城池攻占
不得不說,這道題目是真的難,真不愧它的 省選 noi 的紫色大火題!花了我晚自習前半節課看題解,寫 又花了我半節晚自習調 真的心態 基本上改得和題解完全一樣了我才過了這道題!真的煩。沒事,那接下來我來完全把這道題搞透。part 1 理解題目 至少我一開始不知道為什麼要用左偏樹,甚至我看題解一開始也都...
洛谷P3261 JLOI2015 城池攻占
思路分析 由於這道題的資料範圍是n,m 3e5,所以我們直接輸入乙個模擬乙個是會超時的,但是我們可以在輸入所有的士兵之後把同在乙個節點的士兵一起處理,我們可以考慮建乙個堆,從深度最大的節點開始,維護乙個節點內的士兵的最小戰鬥力值,如果戰鬥力最小的士兵都能存活下來,那麼在堆中的其他士兵一定可以活下來,...
洛谷P3261 JLOI2015 城池攻占
題目大意 有 n 個點的樹,第 i 個節點有乙個權值 h i m 個騎士,第 i 個騎士攻擊力為 v i 乙個騎士可以把從它開始的連續的父親中比它小的節點攻破,攻破乙個節點可以把攻擊力加或乘乙個數 乘的數大於 0 每個騎士獨立 問每個騎士可以攻破多少個點,每個點會阻擋住多少個騎士。題解 可以把所有騎...