Problem:
Area Folding
You are given one polygonal line, which is a collection of line segments.
Your task is to calculate the sum of areas  enclosed by the polygonal line.
A point is defined to be "enclosed" if and only if the point is unreachable without crossing at least one line segment from the point at infinity.
Input
The first line contains one integers
N
(2 ≤ N ≤ 100)
.
N
is the number of segments.
Each of the following
N
lines consists of two integers
X
i
and
Y
i
(-10
5
≤ X
i
, Y
i
≤ 10
5
, 1 ≤ i ≤ N)
which represents a vertex.
A polygonal line is the segments  which connect
(X
j
, Y
j
)
and
(X
j+1
, Y
j+1
)
((X
j
, Y
j
) ≠ (X
j+1
, Y
j+1
), 1 ≤ j ≤ N-1)
.
The distance between a segment
S
j
and all  vertices except the end points on segment
S
j
is guaranteed to be greater than 0.01.
Output
Output the answer in a line.
The answer may be printed with an arbitrary number of decimal digits, but may not contain an absolute or relative error greater than or equal to
10
-6
.
Sample Input 1
5
0 0
1 1
1 0
0 1
0 0
Output for the Sample Input 1
0.5
Sample Input 2
5
0 0
1 1
1 0
0 1
1 0
Output for the Sample Input 2
0.25
Sample Input 3
21
1 1
-1 1
-1 2
-2 2
-2 1
-1 1
-1 -1
-2 -1
-2 -2
-1 -2
-1 -1
1 -1
1 -2
2 -2
2 -1
1 -1
1 1
2 1
2 2
1 2
1 1
Output for the Sample Input 3
8
Sample Input 4
16
0 0
1 0
1 1
0 1
0 2
0 3
1 3
1 2
2 2
2 3
3 3
3 2
3 1
2 1
2 0
3 0
Output for the Sample Input 4
0
Sample Input 5
7
26 52
33 12
-51 68
16 61
43 -26
87 24
12 10
Output for the Sample Input 5
2714.840579710

Submitted solutions:

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cassert>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<int> Vint;
typedef std::vector<ll> Vll;
typedef std::vector<bool> Vbool;
const ll INF = 1e17;
const int LEN = 105;
const ld TOL = 1e-25;
inline int sign(const ll& x) { return x < 0 ? -1 : x > 0; }
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
ll gcd(ll a, ll b) { while (b) { ll tmp = a % b; a = b; b = tmp; } return a; }

#define __FUCK__ ;
#define WHAT_THE_FUCK
//#define DEBUG

int N, M;
struct BigPos {//what the fuck??? holy shit fucking floating point accuracy error!!
	ll x, y, den;
	BigPos(ll X = 0, ll Y = 0, ll D = 1) : x(X), y(Y), den(D) {}
	bool operator == (const BigPos& p) const { return x == p.x && y == p.y; }
	bool operator != (const BigPos& p) const { return x != p.x || y != p.y; }
	bool operator < (const BigPos& p) const { return x == p.x ? y < p.y : x < p.x; }
	bool operator <= (const BigPos& p) const { return *this < p || *this == p; }
	BigPos operator + (const BigPos& p) const { return { x + p.x, y + p.y }; }
	BigPos operator - (const BigPos& p) const { return { x - p.x, y - p.y }; }
	BigPos operator * (const ll& n) const { return { x * n, y * n }; }
	BigPos operator / (const ll& n) const { return { x / n, y / n }; }
	ll operator * (const BigPos& p) const { return x * p.x + y * p.y; }
	ll operator / (const BigPos& p) const { return x * p.y - y * p.x; }
	ll Euc() const { return x * x + y * y; }
	friend std::istream& operator >> (std::istream& is, BigPos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const BigPos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
} C[LEN]; const BigPos BO = { 0, 0, 1 }; const BigPos BINVAL = { 0, 0, 0 };
ll cross(const BigPos& d1, const BigPos& d2, const BigPos& d3) { return (d2 - d1) / (d3 - d2); }
ll cross(const BigPos& d1, const BigPos& d2, const BigPos& d3, const BigPos& d4) { return (d2 - d1) / (d4 - d3); }
ll dot(const BigPos& d1, const BigPos& d2, const BigPos& d3) { return (d2 - d1) * (d3 - d2); }
int ccw(const BigPos& d1, const BigPos& d2, const BigPos& d3) { ll ret = cross(d1, d2, d3); return sign(ret); }
int ccw(const BigPos& d1, const BigPos& d2, const BigPos& d3, const BigPos& d4) { ll ret = cross(d1, d2, d3, d4); return sign(ret); }
bool on_seg_strong(const BigPos& d1, const BigPos& d2, const BigPos& d3) { return !ccw(d1, d2, d3) && dot(d1, d3, d2) >= 0; }
bool collinear(const BigPos& d1, const BigPos& d2, const BigPos& d3, const BigPos& d4) { return !ccw(d1, d2, d3) && !ccw(d1, d2, d4); }
bool intersect(const BigPos& s1, const BigPos& s2, const BigPos& d1, const BigPos& d2) {
	bool f1 = ccw(s1, s2, d1) * ccw(s2, s1, d2) > 0;
	bool f2 = ccw(d1, d2, s1) * ccw(d2, d1, s2) > 0;
	bool f3 = on_seg_strong(s1, s2, d1) ||
		on_seg_strong(s1, s2, d2) ||
		on_seg_strong(d1, d2, s1) ||
		on_seg_strong(d1, d2, s2);
	return (f1 && f2) || f3;
}
BigPos intersection(const BigPos& p1, const BigPos& p2, const BigPos& q1, const BigPos& q2) {
	if (p1 == q1 || p1 == q2) return p1;
	if (p2 == q1 || p2 == q2) return p2;
	ll a1 = cross(q1, q2, p1);
	ll a2 = -cross(q1, q2, p2);
	ll x = p1.x * a2 + p2.x * a1;
	ll y = p1.y * a2 + p2.y * a1;
	ll den = a1 + a2;
	ll gcd_ = gcd(std::abs(x), std::abs(den));
	gcd_ = gcd(std::abs(y), gcd_);
	x /= gcd_; y /= gcd_; den /= gcd_;
	return BigPos(x, y, den);
}
struct BigSeg {
	BigPos a, b;
	bool operator < (const BigSeg& s) const {
		ll tq;
		if (tq = ccw(a, b, s.a, s.b)) return tq > 0;
		if (collinear(a, b, s.a, s.b)) {
			if (a == s.a) return b < s.b;
			return a < s.a;
		}
		return ccw(a, b, s.a) > 0;
	}
	friend std::istream& operator >> (std::istream& is, BigSeg& s) { is >> s.a >> s.b; return is; }
} B[LEN];
BigPos intersection(const BigSeg& s1, const BigSeg& s2) {
	if (!intersect(s1.a, s1.b, s2.a, s2.b)) return BINVAL;
	return intersection(s1.a, s1.b, s2.a, s2.b);
}
bool collinear(const BigSeg& s1, const BigSeg& s2) { return collinear(s1.a, s1.b, s2.a, s2.b); }
struct Pos {
	ld x, y;
	int i;
	bool rv;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) { i = -1, rv = 0; }
	//bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	//bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	//bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	bool operator == (const Pos& p) const { return x == p.x && y == p.y; }
	bool operator != (const Pos& p) const { return x != p.x || y != p.y; }
	bool operator < (const Pos& p) const { return x == p.x ? y < p.y : x < p.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	ld xy() const { return x * y; }
	Pos rot(ld the) { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2l(y, x); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
} p0, p1, key, vec; const Pos O = Pos(0, 0); const Pos INVAL = Pos(INF, INF);
typedef std::vector<Pos> Polygon;
Pos conv(const BigPos& b) {
	ld x = 1. * b.x / b.den;
	ld y = 1. * b.y / b.den;
	return Pos(x, y);
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = cross(d1, d2, d3); return sign(ret); }
bool cmpr(const Pos& p, const Pos& q) {
	ld tp = p.rad();
	ld tq = q.rad();
	return tp == tq ? p.rv > q.rv : tp < tq;
}
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = dot(d1, d3, d2); return !ccw(d1, d2, d3) && sign(ret) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = dot(d1, d3, d2); return !ccw(d1, d2, d3) && sign(ret) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
bool intersect(const Pos& s1, const Pos& s2, const Pos& d1, const Pos& d2) {
	bool f1 = ccw(s1, s2, d1) * ccw(s2, s1, d2) > 0;
	bool f2 = ccw(d1, d2, s1) * ccw(d2, d1, s2) > 0;
	//return f1 && f2;
	bool f3 = on_seg_strong(s1, s2, d1) ||
		on_seg_strong(s1, s2, d2) ||
		on_seg_strong(d1, d2, s1) ||
		on_seg_strong(d1, d2, s2);
	return (f1 && f2) || f3;
}
int inner_check(const Polygon& H, const Pos& p) {//concave
	int sz = H.size(), cnt = 0;
	for (int i = 0; i < sz; i++) {
		Pos cur = H[i], nxt = H[(i + 1) % sz];
		if (on_seg_strong(cur, nxt, p)) return 1;
		if (cur.y == nxt.y) continue;
		if (nxt.y < cur.y) std::swap(cur, nxt);
		if (nxt.y <= p.y || cur.y > p.y) continue;
		cnt += ccw(cur, nxt, p) > 0;
	}
	return (cnt & 1) * 2;
}
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
struct Seg {
	Pos a, b;
	int i;
	Seg(Pos A = Pos(), Pos B = Pos()) : a(A), b(B) { i = -1; }
	Pos inx(const Seg& o) const { return intersection(a, b, o.a, o.b); }
} seg[LEN], frag[LEN * LEN * 10];
Polygon INX[LEN];
void inx_sort(Polygon& INX, const Pos& a) {
	std::sort(INX.begin(), INX.end(), [&](const Pos& p, const Pos& q) -> bool {
		return (a - p).Euc() < (a - q).Euc();
		});
	INX.erase(unique(INX.begin(), INX.end()), INX.end());
}
int I, I0;
std::map<Pos, Polygon> map_pos;
ld A[LEN * LEN + 10];
Polygon cell[LEN * LEN + 10]; int ci;
int V[LEN * LEN * 10];
Vint GS[LEN * LEN * 10];
void dfs(const int& i, int v) {
	V[v] = 1;
	cell[i].push_back(frag[v].a);
	for (const int& w : GS[v]) {
		if (V[w]) continue;
		dfs(i, w);
	}
	return;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	std::cin >> N;
	for (int i = 0; i < N; i++) std::cin >> C[i];
	for (int i = 0; i < N - 1; i++) {
		BigPos a = C[i], b = C[i + 1];
		if (b < a) std::swap(a, b);
		B[i] = { a, b };
	}
	N--;
	Vbool F(N, 1);
	std::sort(B, B + N);
	for (int i = 0; i < N - 1; i++) {
		if (collinear(B[i], B[i + 1])) {
			if (B[i].b < B[i + 1].a) continue;
			if (B[i].a == B[i + 1].a) F[i] = 0;
			else if (B[i + 1].a <= B[i].b) {
				F[i] = 0;
				B[i + 1].a = std::min(B[i].a, B[i + 1].a);
				B[i + 1].b = std::max(B[i].b, B[i + 1].b);
			}
		}
	}
	std::vector<BigSeg> tmp;
	for (int i = 0; i < N; i++) if (F[i]) tmp.push_back(B[i]);
	N = tmp.size();
	for (int i = 0; i < N; i++) B[i] = tmp[i];
	for (int i = 0; i < N; i++) {
		B[i].a.den = B[i].b.den = 1;
		seg[i].a = conv(B[i].a);
		seg[i].b = conv(B[i].b);
		seg[i].i = i;
		seg[i].a.i = i;
		seg[i].b.i = i;
	}
	Polygon INXS;
	for (int i = 0; i < N; i++) {
		for (int j = i + 1; j < N; j++) {
			BigPos inx = intersection(B[i], B[j]);
			if (inx.den) {
#ifdef DEBUG
				std::cout << "FUUUUCK!!!\n";
				std::cout << "FUCK:: S[i].a:: " << B[i].a << " S[i].b:: " << B[i].b << "\n";
				std::cout << "FUCK:: S[j].a:: " << B[j].a << " S[j].b:: " << B[j].b << "\n";
				std::cout << "FUCK:: inx:: " << conv(inx) << "\n";
				std::cout << "FUUUUCK!!!\n";
#endif
				Pos X = conv(inx);
				INX[i].push_back(X);
				INX[j].push_back(X);
				INXS.push_back(X);
			}
		}
	}
	std::sort(INXS.begin(), INXS.end());
	INXS.erase(unique(INXS.begin(), INXS.end()), INXS.end());
	I = 0;
	for (int i = 0; i < N; i++) {
		inx_sort(INX[i], seg[i].a);
		Polygon& v = INX[i];
		int sz = v.size();
		for (int j = 0; j < sz - 1; j++) {
			frag[I] = Seg(v[j], v[j + 1]);
			frag[I].i = I;
			I++;
		}
	}
	I0 = I;
	for (int i = 0; i < N; i++) {
		Polygon& v = INX[i];
		int sz = v.size();
		for (int j = 0; j < sz - 1; j++) {
			frag[I] = Seg(v[j + 1], v[j]);
			frag[I].i = I;
			I++;
		}
	}
	for (int i = 0; i < I; i++) {
		key = frag[i].a;
		vec = frag[i].b - frag[i].a;
		vec.i = frag[i].i;
		map_pos[key].push_back(vec);

		key = frag[i].b;
		vec = frag[i].a - frag[i].b;
		vec.i = frag[i].i;
		vec.rv = 1;
		map_pos[key].push_back(vec);
	}
	for (const Pos& key : INXS) {
		Polygon& v = map_pos[key];
		std::sort(v.begin(), v.end(), cmpr);
		int sz = v.size();
#ifdef DEBUG
		std::cout << "DEBUG:: key:: " << key << "\n";
		std::cout << "DEBUG:: sz:: " << sz << "\n";
		for (int k = 0; k < sz; k++) {
			std::cout << "v[" << k << "]:: " << v[k] << " i:: " << v[k].i << " rv:: " << v[k].rv << "\n";
		}
		std::cout << "FUCK::\n";
#endif
		assert(!(sz & 1));
		for (int j = 0; j < sz; j += 2) {
			Pos cur = v[(j - 1 + sz) % sz], nxt = v[j];
			//assert(cur.rv != nxt.rv);
			GS[nxt.i].push_back(cur.i);
		}
	}
	memset(V, 0, sizeof V);
	ci = 0;
	for (int i = 0; i < I; i++) {
		if (!V[i]) {
			dfs(ci, i);
			A[ci] = area(cell[ci]);
#ifdef DEBUG
			std::cout << "FUCK:: i:: " << i << " sz:: " << cell[ci].size() << "\n";
			//for (const Pos& p : cell[ci]) std::cout << p << "\n";
			std::cout << "FUCK:: A[" << ci << "]:: " << A[ci] << "\n";
#endif
			if (0 == A[ci]) {
				cell[ci].clear();
				A[ci] = 0;
				ci--;
			}
			ci++;
		}
	}
	ld ret = 0;
	for (int i = 0; i < ci; i++) if (A[i] > 0) ret += A[i];
	std::cout << ret * .5 << "\n";
	return;
}
int main() { solve(); return 0; }//boj22485 Area Folding
accuracy: 1
time_ms: 10
memory_kb: 14644
final_rank: 7

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cassert>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<int> Vint;
typedef std::vector<ll> Vll;
typedef std::vector<bool> Vbool;
const ll INF = 1e17;
const int LEN = 105;
const ld TOL = 1e-25;
inline int sign(const ll& x) { return x < 0 ? -1 : x > 0; }
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
ll gcd(ll a, ll b) { while (b) { ll tmp = a % b; a = b; b = tmp; } return a; }

#define __FUCK__ ;
#define WHAT_THE_FUCK
//#define DEBUG

int N, M;
struct BigPos {//what the fuck??? holy shit fucking floating point accuracy error!!
	ll x, y, den;
	BigPos(ll X = 0, ll Y = 0, ll D = 1) : x(X), y(Y), den(D) {}
	bool operator == (const BigPos& p) const { return x == p.x && y == p.y; }
	bool operator != (const BigPos& p) const { return x != p.x || y != p.y; }
	bool operator < (const BigPos& p) const { return x == p.x ? y < p.y : x < p.x; }
	bool operator <= (const BigPos& p) const { return *this < p || *this == p; }
	BigPos operator + (const BigPos& p) const { return { x + p.x, y + p.y }; }
	BigPos operator - (const BigPos& p) const { return { x - p.x, y - p.y }; }
	BigPos operator * (const ll& n) const { return { x * n, y * n }; }
	BigPos operator / (const ll& n) const { return { x / n, y / n }; }
	ll operator * (const BigPos& p) const { return x * p.x + y * p.y; }
	ll operator / (const BigPos& p) const { return x * p.y - y * p.x; }
	ll Euc() const { return x * x + y * y; }
	friend std::istream& operator >> (std::istream& is, BigPos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const BigPos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
} C[LEN]; const BigPos BO = { 0, 0, 1 }; const BigPos BINVAL = { 0, 0, 0 };
ll cross(const BigPos& d1, const BigPos& d2, const BigPos& d3) { return (d2 - d1) / (d3 - d2); }
ll cross(const BigPos& d1, const BigPos& d2, const BigPos& d3, const BigPos& d4) { return (d2 - d1) / (d4 - d3); }
ll dot(const BigPos& d1, const BigPos& d2, const BigPos& d3) { return (d2 - d1) * (d3 - d2); }
int ccw(const BigPos& d1, const BigPos& d2, const BigPos& d3) { ll ret = cross(d1, d2, d3); return sign(ret); }
int ccw(const BigPos& d1, const BigPos& d2, const BigPos& d3, const BigPos& d4) { ll ret = cross(d1, d2, d3, d4); return sign(ret); }
bool on_seg_strong(const BigPos& d1, const BigPos& d2, const BigPos& d3) { return !ccw(d1, d2, d3) && dot(d1, d3, d2) >= 0; }
bool collinear(const BigPos& d1, const BigPos& d2, const BigPos& d3, const BigPos& d4) { return !ccw(d1, d2, d3) && !ccw(d1, d2, d4); }
bool intersect(const BigPos& s1, const BigPos& s2, const BigPos& d1, const BigPos& d2) {
	bool f1 = ccw(s1, s2, d1) * ccw(s2, s1, d2) > 0;
	bool f2 = ccw(d1, d2, s1) * ccw(d2, d1, s2) > 0;
	bool f3 = on_seg_strong(s1, s2, d1) ||
		on_seg_strong(s1, s2, d2) ||
		on_seg_strong(d1, d2, s1) ||
		on_seg_strong(d1, d2, s2);
	return (f1 && f2) || f3;
}
BigPos intersection(const BigPos& p1, const BigPos& p2, const BigPos& q1, const BigPos& q2) {
	if (p1 == q1 || p1 == q2) return p1;
	if (p2 == q1 || p2 == q2) return p2;
	ll a1 = cross(q1, q2, p1);
	ll a2 = -cross(q1, q2, p2);
	ll x = p1.x * a2 + p2.x * a1;
	ll y = p1.y * a2 + p2.y * a1;
	ll den = a1 + a2;
	ll gcd_ = gcd(std::abs(x), std::abs(den));
	gcd_ = gcd(std::abs(y), gcd_);
	x /= gcd_; y /= gcd_; den /= gcd_;
	return BigPos(x, y, den);
}
struct BigSeg {
	BigPos a, b;
	bool operator < (const BigSeg& s) const {
		ll tq;
		if (tq = ccw(a, b, s.a, s.b)) return tq > 0;
		if (collinear(a, b, s.a, s.b)) {
			if (a == s.a) return b < s.b;
			return a < s.a;
		}
		return ccw(a, b, s.a) > 0;
	}
	friend std::istream& operator >> (std::istream& is, BigSeg& s) { is >> s.a >> s.b; return is; }
} B[LEN];
BigPos intersection(const BigSeg& s1, const BigSeg& s2) {
	if (!intersect(s1.a, s1.b, s2.a, s2.b)) return BINVAL;
	return intersection(s1.a, s1.b, s2.a, s2.b);
}
bool collinear(const BigSeg& s1, const BigSeg& s2) { return collinear(s1.a, s1.b, s2.a, s2.b); }
struct Pos {
	ld x, y;
	int i;
	bool rv;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) { i = -1, rv = 0; }
	//bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	//bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	//bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	bool operator == (const Pos& p) const { return x == p.x && y == p.y; }
	bool operator != (const Pos& p) const { return x != p.x || y != p.y; }
	bool operator < (const Pos& p) const { return x == p.x ? y < p.y : x < p.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	ld xy() const { return x * y; }
	Pos rot(ld the) { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2l(y, x); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
} p0, p1, key, vec; const Pos O = Pos(0, 0); const Pos INVAL = Pos(INF, INF);
typedef std::vector<Pos> Polygon;
Pos conv(const BigPos& b) {
	ld x = 1. * b.x / b.den;
	ld y = 1. * b.y / b.den;
	return Pos(x, y);
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = cross(d1, d2, d3); return sign(ret); }
bool cmpr(const Pos& p, const Pos& q) {
	//bool f1 = O < p;
	//bool f2 = O < q;
	//if (f1 != f2) return f1;
	//int tq = ccw(O, p, q);
	//return !tq ? p.rv > q.rv : tq > 0;
	ld tp = p.rad();
	ld tq = q.rad();
	return tp == tq ? p.rv > q.rv : tp < tq;
}
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = dot(d1, d3, d2); return !ccw(d1, d2, d3) && sign(ret) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { ld ret = dot(d1, d3, d2); return !ccw(d1, d2, d3) && sign(ret) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
bool intersect(const Pos& s1, const Pos& s2, const Pos& d1, const Pos& d2) {
	bool f1 = ccw(s1, s2, d1) * ccw(s2, s1, d2) > 0;
	bool f2 = ccw(d1, d2, s1) * ccw(d2, d1, s2) > 0;
	//return f1 && f2;
	bool f3 = on_seg_strong(s1, s2, d1) ||
		on_seg_strong(s1, s2, d2) ||
		on_seg_strong(d1, d2, s1) ||
		on_seg_strong(d1, d2, s2);
	return (f1 && f2) || f3;
}
int inner_check(const Polygon& H, const Pos& p) {//concave
	int sz = H.size(), cnt = 0;
	for (int i = 0; i < sz; i++) {
		Pos cur = H[i], nxt = H[(i + 1) % sz];
		if (on_seg_strong(cur, nxt, p)) return 1;
		if (cur.y == nxt.y) continue;
		if (nxt.y < cur.y) std::swap(cur, nxt);
		if (nxt.y <= p.y || cur.y > p.y) continue;
		cnt += ccw(cur, nxt, p) > 0;
	}
	return (cnt & 1) * 2;
}
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
struct Seg {
	Pos a, b;
	int i;
	Seg(Pos A = Pos(), Pos B = Pos()) : a(A), b(B) { i = -1; }
	Pos inx(const Seg& o) const { return intersection(a, b, o.a, o.b); }
} seg[LEN], frag[LEN * LEN * 10];
Polygon INX[LEN];
void inx_sort(Polygon& INX, const Pos& a) {
	std::sort(INX.begin(), INX.end(), [&](const Pos& p, const Pos& q) -> bool {
		return (a - p).Euc() < (a - q).Euc();
		});
	INX.erase(unique(INX.begin(), INX.end()), INX.end());
}
int I, I0;
std::map<Pos, Polygon> map_pos;
ld A[LEN * LEN + 10];
Polygon cell[LEN * LEN + 10]; int ci;
std::set<int> cell_i[LEN * LEN + 10];
int P[LEN * LEN + 10];//disjoint set
int find(int i) { return P[i] < 0 ? i : P[i] = find(P[i]); }
bool join(int i, int j) {
	i = find(i), j = find(j);
	if (i == j) return 0;
	if (P[i] < P[j]) P[i] += P[j], P[j] = i;
	else P[j] += P[i], P[i] = j;
	return 1;
}
int V[LEN * LEN * 10];
Vint GS[LEN * LEN * 10];
void dfs(const int& i, int v) {
	V[v] = 1;
	cell[i].push_back(frag[v].a);
	cell_i[i].insert(v);
	for (const int& w : GS[v]) {
		if (V[w]) continue;
		dfs(i, w);
	}
	return;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	std::cin >> N;
	for (int i = 0; i < N; i++) std::cin >> C[i];
	for (int i = 0; i < N - 1; i++) {
		BigPos a = C[i], b = C[i + 1];
		if (b < a) std::swap(a, b);
		B[i] = { a, b };
		//B[i].a.den = B[i].b.den = 1;
		//seg[i].a = conv(B[i].a);
		//seg[i].b = conv(B[i].b);
		//seg[i].i = i;
		//seg[i].a.i = i;
		//seg[i].b.i = i;
	}
	N--;
	Vbool F(N, 1);
	std::sort(B, B + N);
	for (int i = 0; i < N - 1; i++) {
		if (collinear(B[i], B[i + 1])) {
			if (B[i].b < B[i + 1].a) continue;
			if (B[i].a == B[i + 1].a) F[i] = 0;
			else if (B[i + 1].a <= B[i].b) {
				F[i] = 0;
				B[i + 1].a = std::min(B[i].a, B[i + 1].a);
				B[i + 1].b = std::max(B[i].b, B[i + 1].b);
			}
		}
	}
	std::vector<BigSeg> tmp;
	for (int i = 0; i < N; i++) if (F[i]) tmp.push_back(B[i]);
	N = tmp.size();
	for (int i = 0; i < N; i++) B[i] = tmp[i];
	for (int i = 0; i < N; i++) {
		//BigPos a = C[i], b = C[i + 1];
		//if (b < a) std::swap(a, b);
		//B[i] = { a, b };
		B[i].a.den = B[i].b.den = 1;
		seg[i].a = conv(B[i].a);
		seg[i].b = conv(B[i].b);
		seg[i].i = i;
		seg[i].a.i = i;
		seg[i].b.i = i;
	}
	Polygon INXS;
	for (int i = 0; i < N; i++) {
		for (int j = i + 1; j < N; j++) {
			BigPos inx = intersection(B[i], B[j]);
			if (inx.den) {
#ifdef DEBUG
				std::cout << "FUUUUCK!!!\n";
				std::cout << "FUCK:: S[i].a:: " << B[i].a << " S[i].b:: " << B[i].b << "\n";
				std::cout << "FUCK:: S[j].a:: " << B[j].a << " S[j].b:: " << B[j].b << "\n";
				std::cout << "FUCK:: inx:: " << conv(inx) << "\n";
				std::cout << "FUUUUCK!!!\n";
#endif
				Pos X = conv(inx);
				INX[i].push_back(X);
				INX[j].push_back(X);
				INXS.push_back(X);
			}
		}
	}
	std::sort(INXS.begin(), INXS.end());
	INXS.erase(unique(INXS.begin(), INXS.end()), INXS.end());
	I = 0;
	for (int i = 0; i < N; i++) {
		inx_sort(INX[i], seg[i].a);
		Polygon& v = INX[i];
		int sz = v.size();
		for (int j = 0; j < sz - 1; j++) {
			frag[I] = Seg(v[j], v[j + 1]);
			frag[I].i = I;
			I++;
		}
	}
	I0 = I;
	for (int i = 0; i < N; i++) {
		Polygon& v = INX[i];
		int sz = v.size();
		for (int j = 0; j < sz - 1; j++) {
			frag[I] = Seg(v[j + 1], v[j]);
			frag[I].i = I;
			I++;
		}
	}
	for (int i = 0; i < I; i++) {
		key = frag[i].a;
		vec = frag[i].b - frag[i].a;
		vec.i = frag[i].i;
		map_pos[key].push_back(vec);

		key = frag[i].b;
		vec = frag[i].a - frag[i].b;
		vec.i = frag[i].i;
		vec.rv = 1;
		map_pos[key].push_back(vec);
	}
	for (const Pos& key : INXS) {
		Polygon& v = map_pos[key];
		std::sort(v.begin(), v.end(), cmpr);
		int sz = v.size();
#ifdef DEBUG
		std::cout << "DEBUG:: key:: " << key << "\n";
		std::cout << "DEBUG:: sz:: " << sz << "\n";
		for (int k = 0; k < sz; k++) {
			std::cout << "v[" << k << "]:: " << v[k] << " i:: " << v[k].i << " rv:: " << v[k].rv << "\n";
		}
		std::cout << "FUCK::\n";
#endif
		assert(!(sz & 1));
		for (int j = 0; j < sz; j += 2) {
			Pos cur = v[(j - 1 + sz) % sz], nxt = v[j];
			//assert(cur.rv != nxt.rv);
			GS[nxt.i].push_back(cur.i);
		}
	}
	memset(V, 0, sizeof V);
	ci = 0;
	for (int i = 0; i < I; i++) {
		if (!V[i]) {
			dfs(ci, i);
			A[ci] = area(cell[ci]);
#ifdef DEBUG
			std::cout << "FUCK:: i:: " << i << " sz:: " << cell[ci].size() << "\n";
			//for (const Pos& p : cell[ci]) std::cout << p << "\n";
			std::cout << "FUCK:: A[" << ci << "]:: " << A[ci] << "\n";
#endif
			if (0 == A[ci]) {
				cell[ci].clear();
				cell_i[ci].clear();
				A[ci] = 0;
				ci--;
			}
			ci++;
		}
	}
	ld ret = 0;
	for (int i = 0; i < ci; i++) if (A[i] > 0) ret += A[i];
	std::cout << ret * .5 << "\n";
	return;
}
int main() { solve(); return 0; }//boj22485 Area Folding
accuracy: 1
time_ms: 10
memory_kb: 15820
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
const double eps = 0.000001;
int sign(double x){
  if (x > eps){
    return 1;
  } else if (x < -eps){
    return -1;
  } else {
    return 0;
  }
}
struct point{
  double x, y;
  point(){
  }
  point(double x, double y): x(x), y(y){
  }
  point operator +(point P){
    return point(x + P.x, y + P.y);
  }
  point operator -(point P){
    return point(x - P.x, y - P.y);
  }
  point operator *(double k){
    return point(x * k, y * k);
  }
  point operator /(double k){
    return point(x / k, y / k);
  }
};
double abs(point P){
  return sqrt(P.x * P.x + P.y * P.y);
}
double dist(point P, point Q){
  return abs(Q - P);
}
point rotate(point P, double t){
  return point(P.x * cos(t) - P.y * sin(t), P.x * sin(t) + P.y * cos(t));
}
double cross(point P, point Q){
  return P.x * Q.y - P.y * Q.x;
}
struct line{
  point A, B;
  line(){
  }
  line(point A, point B): A(A), B(B){
  }
};
point vec(line L){
  return L.B - L.A;
}
bool is_parallel(line L1, line L2){
  return abs(cross(vec(L1), vec(L2))) < eps;
}
bool segment_line_intersect(line L1, line L2){
  return sign(cross(L1.A - L2.A, vec(L2))) * sign(cross(L1.B - L2.A, vec(L2))) <= 0;
}
bool segment_intersect(line L1, line L2){
  return segment_line_intersect(L1, L2) && segment_line_intersect(L2, L1);
}
point line_intersection(line L1, line L2){
  return L1.A + vec(L1) * cross(L2.A - L1.A, vec(L2)) / cross(vec(L1), vec(L2));
}
vector<double> unique_eps(vector<double> A){
  int N = A.size();
  sort(A.begin(), A.end());
  vector<double> A2;
  A2.push_back(A[0]);
  for (int i = 1; i < N; i++){
    if (A[i] - A[i - 1] > eps){
      A2.push_back(A[i]);
    }
  }
  return A2;
}
template <typename T>
struct slab_decomposition{
  function<T(T, T)> f;
  T e;
  vector<pair<line, T>> S;
  vector<double> X;
  int N;
  vector<vector<double>> Y;
  vector<int> P;
  vector<vector<tuple<int, int, T>>> E;
  slab_decomposition(function<T(T, T)> f, T e): f(f), e(e){
  }
  void add_segment(line s, T x){
    S.push_back(make_pair(s, x));
  }
  vector<vector<pair<T, int>>> build(){
    int M = S.size();
    for (int i = 0; i < M; i++){
      if (S[i].first.A.x > S[i].first.B.x){
        swap(S[i].first.A, S[i].first.B);
      }
    }
    for (int i = 0; i < M; i++){
      X.push_back(S[i].first.A.x);
      X.push_back(S[i].first.B.x);
    }
    for (int i = 0; i < M; i++){
      for (int j = i + 1; j < M; j++){
        if (!is_parallel(S[i].first, S[j].first) && segment_intersect(S[i].first, S[j].first)){
          X.push_back(line_intersection(S[i].first, S[j].first).x);
        }
      }
    }
    X = unique_eps(X);
    N = X.size();
    vector<int> L(M), R(M);
    for (int i = 0; i < M; i++){
      L[i] = lower_bound(X.begin(), X.end(), S[i].first.A.x - eps) - X.begin();
      R[i] = lower_bound(X.begin(), X.end(), S[i].first.B.x - eps) - X.begin();
    }
    vector<vector<double>> A(M, vector<double>(N));
    Y.resize(N);
    for (int i = 0; i < M; i++){
      for (int j = L[i]; j <= R[i]; j++){
        A[i][j] = line_intersection(S[i].first, line(point(X[j], 0), point(X[j], 1))).y;
        Y[j].push_back(A[i][j]);
      }
    }
    for (int i = 0; i < N; i++){
      Y[i] = unique_eps(Y[i]);
    }
    vector<vector<int>> B(M, vector<int>(N));
    for (int i = 0; i < M; i++){
      for (int j = L[i]; j <= R[i]; j++){
        B[i][j] = lower_bound(Y[j].begin(), Y[j].end(), A[i][j] - eps) - Y[j].begin();
      }
    }
    E.resize(N - 1);
    for (int i = 0; i < N - 1; i++){
      E[i].push_back(make_tuple(-1, -1, e));
    }
    for (int i = 0; i < M; i++){
      for (int j = L[i]; j < R[i]; j++){
        E[j].push_back(make_tuple(B[i][j], B[i][j + 1], S[i].second));
      }
    }
    for (int i = 0; i < N - 1; i++){
      E[i].push_back(make_tuple(Y[i].size(), Y[i + 1].size(), e));
    }
    for (int i = 0; i < N - 1; i++){
      sort(E[i].begin(), E[i].end());
      if (!E[i].empty()){
        vector<tuple<int, int, T>> E2;
        int cnt = E[i].size();
        E2.push_back(E[i][0]);
        for (int j = 1; j < cnt; j++){
          if (get<0>(E[i][j - 1]) == get<0>(E[i][j]) && get<1>(E[i][j - 1]) == get<1>(E[i][j])){
            get<2>(E2.back()) = f(get<2>(E2.back()), get<2>(E[i][j]));
          } else {
            E2.push_back(E[i][j]);
          }
        }
        E[i] = E2;
      }
    }
    P.resize(N + 2);
    P[0] = 0;
    P[1] = 1;
    for (int i = 0; i < N - 1; i++){
      P[i + 2] = P[i + 1] + E[i].size() - 1;
    }
    P[N + 1] = P[N] + 1;
    vector<vector<int>> idL(N), idR(N);
    for (int i = 0; i < N; i++){
      idL[i] = vector<int>(Y[i].size() + 1);
      idR[i] = vector<int>(Y[i].size() + 1);
    }
    idL[0] = vector<int>(Y[0].size() + 1, 0);
    for (int i = 0; i < N - 1; i++){
      int cnt = E[i].size();
      for (int j = 0; j < cnt - 1; j++){
        for (int k = get<0>(E[i][j]) + 1; k <= get<0>(E[i][j + 1]); k++){
          idR[i][k] = P[i + 1] + j;
        }
        for (int k = get<1>(E[i][j]) + 1; k <= get<1>(E[i][j + 1]); k++){
          idL[i + 1][k] = P[i + 1] + j;
        }
      }
    }
    idR[N - 1] = vector<int>(Y[N - 1].size() + 1, P[N]);
    int V = P[N + 1];
    vector<vector<pair<T, int>>> G(V);
    for (int i = 0; i <= N; i++){
      for (int j = P[i]; j < P[i + 1] - 1; j++){
        G[j].push_back(make_pair(get<2>(E[i - 1][j - P[i] + 1]), j + 1));
        G[j + 1].push_back(make_pair(get<2>(E[i - 1][j - P[i] + 1]), j));
      }
    }
    for (int i = 0; i < N; i++){
      for (int j = 0; j <= Y[i].size(); j++){
        G[idL[i][j]].push_back(make_pair(e, idR[i][j]));
        G[idR[i][j]].push_back(make_pair(e, idL[i][j]));
      }
    }
    return G;
  }
  int find(point p){
    int x = lower_bound(X.begin(), X.end(), p.x - eps) - X.begin();
    if (x == 0){
      return 0;
    } else if (x == N){
      return P[N];
    } else {
      int ans = P[x];
      for (int i = 1; i < E[x - 1].size() - 1; i++){
        point A(X[x - 1], Y[x - 1][get<0>(E[x - 1][i])]);
        point B(X[x], Y[x][get<1>(E[x - 1][i])]);
        if (cross(B - A, p - A) > 0){
          ans++;
        }
      }
      return ans;
    }
  }
  vector<double> area(){
    int V = P[N + 1];
    vector<double> ans(V, -1);
    for (int i = 0; i < N - 1; i++){
      for(int j = 1; j < E[i].size() - 2; j++){
        double l = Y[i][get<0>(E[i][j + 1])] - Y[i][get<0>(E[i][j])];
        double r = Y[i + 1][get<1>(E[i][j + 1])] - Y[i + 1][get<1>(E[i][j])];
        ans[P[i + 1] + j] = (l + r) * (X[i + 1] - X[i]) / 2;
      }
    }
    return ans;
  }
  vector<double> length(){
    int V = P[N + 1];
    vector<double> ans(V, -1);
    for (int i = 0; i < N - 1; i++){
      for(int j = 1; j < E[i].size() - 1; j++){
        double l = Y[i][get<0>(E[i][j])];
        double r = Y[i + 1][get<1>(E[i][j])];
        ans[P[i + 1] + j - 1] = hypot(X[i + 1] - X[i], r - l);
      }
    }
    return ans;
  }
};
int main(){
  cout << fixed << setprecision(20);
  int N;
  cin >> N;
  vector<point> P(N);
  for (int i = 0; i < N; i++){
    cin >> P[i].x >> P[i].y;
  }
  for (int i = 0; i < N; i++){
    P[i] = rotate(P[i], 0.01);
  }
  slab_decomposition<bool> D(logical_or<>(), false);
  for (int i = 0; i < N - 1; i++){
    D.add_segment(line(P[i], P[i + 1]), true);
  }
  vector<vector<pair<bool, int>>> E = D.build();
  int V = E.size();
  vector<bool> used(V, false);
  used[0] = true;
  queue<int> Q;
  Q.push(0);
  while (!Q.empty()){
    int v = Q.front();
    Q.pop();
    for (pair<bool, int> e : E[v]){
      if (!e.first){
        int w = e.second;
        if (!used[w]){
          used[w] = true;
          Q.push(w);
        }
      }
    }
  }
  vector<double> S = D.area();
  double ans = 0;
  for (int i = 0; i < V; i++){
    if (!used[i]){
      ans += S[i];
    }
  }
  cout << ans << endl;
}
accuracy: 1
time_ms: 20
memory_kb: 22372
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
const double eps = 0.00001;
int sign(double x){
  if (x > eps){
    return 1;
  } else if (x < -eps){
    return -1;
  } else {
    return 0;
  }
}
struct point{
  double x, y;
  point(){
  }
  point(double x, double y): x(x), y(y){
  }
  point operator +(point P){
    return point(x + P.x, y + P.y);
  }
  point operator -(point P){
    return point(x - P.x, y - P.y);
  }
  point operator *(double k){
    return point(x * k, y * k);
  }
  point operator /(double k){
    return point(x / k, y / k);
  }
};
double abs(point P){
  return sqrt(P.x * P.x + P.y * P.y);
}
double dist(point P, point Q){
  return abs(Q - P);
}
point rotate(point P, double t){
  return point(P.x * cos(t) - P.y * sin(t), P.x * sin(t) + P.y * cos(t));
}
double cross(point P, point Q){
  return P.x * Q.y - P.y * Q.x;
}
struct line{
  point A, B;
  line(){
  }
  line(point A, point B): A(A), B(B){
  }
};
point vec(line L){
  return L.B - L.A;
}
bool is_parallel(line L1, line L2){
  return abs(cross(vec(L1), vec(L2))) < eps;
}
bool segment_line_intersect(line L1, line L2){
  return sign(cross(L1.A - L2.A, vec(L2))) * sign(cross(L1.B - L2.A, vec(L2))) <= 0;
}
bool segment_intersect(line L1, line L2){
  return segment_line_intersect(L1, L2) && segment_line_intersect(L2, L1);
}
point line_intersection(line L1, line L2){
  return L1.A + vec(L1) * cross(L2.A - L1.A, vec(L2)) / cross(vec(L1), vec(L2));
}
vector<double> unique_eps(vector<double> A){
  int N = A.size();
  sort(A.begin(), A.end());
  vector<double> A2;
  A2.push_back(A[0]);
  for (int i = 1; i < N; i++){
    if (A[i] - A[i - 1] > eps){
      A2.push_back(A[i]);
    }
  }
  return A2;
}
struct slab_decomposition{
  vector<line> S;
  vector<double> X;
  int N;
  vector<vector<double>> Y;
  vector<int> T;
  vector<vector<pair<int, int>>> E;
  slab_decomposition(){
  }
  void add_segment(line s){
    S.push_back(s);
  }
  vector<vector<pair<int, int>>> build(){
    int M = S.size();
    for (int i = 0; i < M; i++){
      if (S[i].A.x > S[i].B.x){
        swap(S[i].A, S[i].B);
      }
    }
    for (int i = 0; i < M; i++){
      X.push_back(S[i].A.x);
      X.push_back(S[i].B.x);
    }
    for (int i = 0; i < M; i++){
      for (int j = i + 1; j < M; j++){
        if (!is_parallel(S[i], S[j]) && segment_intersect(S[i], S[j])){
          X.push_back(line_intersection(S[i], S[j]).x);
        }
      }
    }
    X = unique_eps(X);
    N = X.size();
    vector<int> L(M), R(M);
    for (int i = 0; i < M; i++){
      L[i] = lower_bound(X.begin(), X.end(), S[i].A.x - eps) - X.begin();
      R[i] = lower_bound(X.begin(), X.end(), S[i].B.x - eps) - X.begin();
    }
    vector<vector<double>> A(M, vector<double>(N));
    Y.resize(N);
    for (int i = 0; i < M; i++){
      for (int j = L[i]; j <= R[i]; j++){
        A[i][j] = line_intersection(S[i], line(point(X[j], 0), point(X[j], 1))).y;
        Y[j].push_back(A[i][j]);
      }
    }
    for (int i = 0; i < N; i++){
      Y[i] = unique_eps(Y[i]);
    }
    vector<vector<int>> B(M, vector<int>(N));
    for (int i = 0; i < M; i++){
      for (int j = L[i]; j <= R[i]; j++){
        B[i][j] = lower_bound(Y[j].begin(), Y[j].end(), A[i][j] - eps) - Y[j].begin();
      }
    }
    E.resize(N - 1);
    for (int i = 0; i < N - 1; i++){
      E[i].push_back(make_pair(-1, -1));
    }
    for (int i = 0; i < M; i++){
      for (int j = L[i]; j < R[i]; j++){
        E[j].push_back(make_pair(B[i][j], B[i][j + 1]));
      }
    }
    for (int i = 0; i < N - 1; i++){
      E[i].push_back(make_pair(Y[i].size(), Y[i + 1].size()));
    }
    for (int i = 0; i < N - 1; i++){
      sort(E[i].begin(), E[i].end());
    }
    T.resize(N + 2);
    T[0] = 0;
    T[1] = 1;
    for (int i = 0; i < N - 1; i++){
      T[i + 2] = T[i + 1] + E[i].size() - 1;
    }
    T[N + 1] = T[N] + 1;
    vector<vector<int>> idL(N), idR(N);
    for (int i = 0; i < N; i++){
      idL[i] = vector<int>(Y[i].size() + 1);
      idR[i] = vector<int>(Y[i].size() + 1);
    }
    idL[0] = vector<int>(Y[0].size() + 1, 0);
    for (int i = 0; i < N - 1; i++){
      int cnt = E[i].size();
      for (int j = 0; j < cnt - 1; j++){
        for (int k = E[i][j].first + 1; k <= E[i][j + 1].first; k++){
          idR[i][k] = T[i + 1] + j;
        }
        for (int k = E[i][j].second + 1; k <= E[i][j + 1].second; k++){
          idL[i + 1][k] = T[i + 1] + j;
        }
      }
    }
    idR[N - 1] = vector<int>(Y[N - 1].size() + 1, T[N]);
    int V = T[N + 1];
    vector<vector<pair<int, int>>> G(V);
    for (int i = 0; i <= N; i++){
      for (int j = T[i]; j < T[i + 1] - 1; j++){
        G[j].push_back(make_pair(1, j + 1));
        G[j + 1].push_back(make_pair(1, j));
      }
    }
    for (int i = 0; i < N; i++){
      for (int j = 0; j <= Y[i].size(); j++){
        G[idL[i][j]].push_back(make_pair(0, idR[i][j]));
        G[idR[i][j]].push_back(make_pair(0, idL[i][j]));
      }
    }
    return G;
  }
  vector<double> area(){
    int V = T[N + 1];
    vector<double> ans(V, -1);
    for (int i = 0; i < N - 1; i++){
      for(int j = 1; j < E[i].size() - 2; j++){
        double l = Y[i][E[i][j + 1].first] - Y[i][E[i][j].first];
        double r = Y[i + 1][E[i][j + 1].second] - Y[i + 1][E[i][j].second];
        ans[T[i + 1] + j] = (l + r) * (X[i + 1] - X[i]) / 2;
      }
    }
    return ans;
  }
};
int main(){
  cout << fixed << setprecision(20);
  int N;
  cin >> N;
  vector<point> P(N);
  for (int i = 0; i < N; i++){
    cin >> P[i].x >> P[i].y;
  }
  for (int i = 0; i < N; i++){
    P[i] = rotate(P[i], 0.01);
  }
  slab_decomposition D;
  for (int i = 0; i < N - 1; i++){
    D.add_segment(line(P[i], P[i + 1]));
  }
  vector<vector<pair<int, int>>> E = D.build();
  int V = E.size();
  vector<bool> used(V, false);
  used[0] = true;
  queue<int> Q;
  Q.push(0);
  while (!Q.empty()){
    int v = Q.front();
    Q.pop();
    for (pair<int, int> e : E[v]){
      if (e.first == 0){
        int w = e.second;
        if (!used[w]){
          used[w] = true;
          Q.push(w);
        }
      }
    }
  }
  vector<double> S = D.area();
  double ans = 0;
  for (int i = 0; i < V; i++){
    if (!used[i]){
      ans += S[i];
    }
  }
  cout << ans << endl;
}
accuracy: 1
time_ms: 20
memory_kb: 21284
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
const double eps = 0.00001;
int sign(double x){
  if (x > eps){
    return 1;
  } else if (x < -eps){
    return -1;
  } else {
    return 0;
  }
}
struct point{
  double x, y;
  point(){
  }
  point(double x, double y): x(x), y(y){
  }
  point operator +(point P){
    return point(x + P.x, y + P.y);
  }
  point operator -(point P){
    return point(x - P.x, y - P.y);
  }
  point operator *(double k){
    return point(x * k, y * k);
  }
  point operator /(double k){
    return point(x / k, y / k);
  }
};
double abs(point P){
  return sqrt(P.x * P.x + P.y * P.y);
}
double dist(point P, point Q){
  return abs(Q - P);
}
point rotate(point P, double t){
  return point(P.x * cos(t) - P.y * sin(t), P.x * sin(t) + P.y * cos(t));
}
double cross(point P, point Q){
  return P.x * Q.y - P.y * Q.x;
}
struct line{
  point A, B;
  line(){
  }
  line(point A, point B): A(A), B(B){
  }
};
point vec(line L){
  return L.B - L.A;
}
bool is_parallel(line L1, line L2){
  return abs(cross(vec(L1), vec(L2))) < eps;
}
bool segment_line_intersect(line L1, line L2){
  return sign(cross(L1.A - L2.A, vec(L2))) * sign(cross(L1.B - L2.A, vec(L2))) <= 0;
}
bool segment_intersect(line L1, line L2){
  return segment_line_intersect(L1, L2) && segment_line_intersect(L2, L1);
}
point line_intersection(line L1, line L2){
  return L1.A + vec(L1) * cross(L2.A - L1.A, vec(L2)) / cross(vec(L1), vec(L2));
}
int main(){
  cout << fixed << setprecision(20);
  int N;
  cin >> N;
  vector<point> P(N);
  for (int i = 0; i < N; i++){
    cin >> P[i].x >> P[i].y;
  }
  for (int i = 0; i < N; i++){
    P[i] = rotate(P[i], 0.01);
  }
  vector<line> L(N - 1);
  for (int i = 0; i < N - 1; i++){
    L[i].A = P[i];
    L[i].B = P[i + 1];
  }
  vector<double> X;
  for (int i = 0; i < N; i++){
    X.push_back(P[i].x);
  }
  for (int i = 0; i < N - 1; i++){
    for (int j = i + 1; j < N - 1; j++){
      if (!is_parallel(L[i], L[j])){
        if (segment_intersect(L[i], L[j])){
          X.push_back(line_intersection(L[i], L[j]).x);
        }
      }
    }
  }
  sort(X.begin(), X.end());
  int cnt = X.size();
  vector<double> X2;
  X2.push_back(X[0]);
  for (int i = 1; i < cnt; i++){
    if (X[i] - X[i - 1] > eps){
      X2.push_back(X[i]);
    }
  }
  X = X2;
  cnt = X.size();
  vector<vector<double>> Y(cnt);
  for (int i = 0; i < N - 1; i++){
    double mn = min(P[i].x, P[i + 1].x);
    double mx = max(P[i].x, P[i + 1].x);
    int l = lower_bound(X.begin(), X.end(), mn - eps) - X.begin();
    int r = lower_bound(X.begin(), X.end(), mx - eps) - X.begin();
    for (int j = l; j <= r; j++){
      line L2(point(X[j], 0), point(X[j], 1));
      point P = line_intersection(L[i], L2);
      Y[j].push_back(P.y);
    }
  }
  for (int i = 0; i < cnt; i++){
    sort(Y[i].begin(), Y[i].end());
    int cnt2 = Y[i].size();
    vector<double> Y2;
    Y2.push_back(Y[i][0]);
    for (int j = 1; j < cnt2; j++){
      if (Y[i][j] - Y[i][j - 1] > eps){
        Y2.push_back(Y[i][j]);
      }
    }
    Y[i] = Y2;
  }
  vector<vector<pair<int, int>>> C(cnt - 1);
  for (int i = 0; i < N - 1; i++){
    double mn = min(P[i].x, P[i + 1].x);
    double mx = max(P[i].x, P[i + 1].x);
    int l = lower_bound(X.begin(), X.end(), mn - eps) - X.begin();
    int r = lower_bound(X.begin(), X.end(), mx - eps) - X.begin();
    for (int j = l; j < r; j++){
      line L2(point(X[j], 0), point(X[j], 1));
      line L3(point(X[j + 1], 0), point(X[j + 1], 1));
      double yl = line_intersection(L[i], L2).y;
      double yr = line_intersection(L[i], L3).y;
      int pl = lower_bound(Y[j].begin(), Y[j].end(), yl - eps) - Y[j].begin();
      int pr = lower_bound(Y[j + 1].begin(), Y[j + 1].end(), yr - eps) - Y[j + 1].begin();
      C[j].push_back(make_pair(pl, pr));
    }
  }
  for (int i = 0; i < cnt - 1; i++){
    sort(C[i].begin(), C[i].end());
  }
  vector<int> S(cnt + 2);
  S[0] = 0;
  S[1] = 1;
  for (int i = 0; i < cnt; i++){
    S[i + 2] = S[i + 1] + C[i].size() + 1;
  }
  S[cnt + 1] = S[cnt] + 1;
  vector<vector<int>> idL(cnt), idR(cnt);
  for (int i = 0; i < cnt; i++){
    idL[i].resize(Y[i].size() + 1);
    idR[i].resize(Y[i].size() + 1);
  }
  idL[0] = vector<int>(Y[0].size() + 1, 0);
  idR[cnt - 1] = vector<int>(Y[cnt - 1].size() + 1, S[cnt]);
  for (int i = 0; i < cnt - 1; i++){
    C[i].insert(C[i].begin(), make_pair(-1, -1));
    C[i].push_back(make_pair(Y[i].size(), Y[i + 1].size()));
    int cnt2 = C[i].size();
    for (int j = 0; j < cnt2 - 1; j++){
      for (int k = C[i][j].first + 1; k <= C[i][j + 1].first; k++){
        idR[i][k] = S[i + 1] + j;
      }
      for (int k = C[i][j].second + 1; k <= C[i][j + 1].second; k++){
        idL[i + 1][k] = S[i + 1] + j;
      }
    }
    C[i].erase(C[i].begin());
    C[i].pop_back();
  }
  int V = S[cnt + 1];
  vector<vector<int>> E(V);
  for (int i = 0; i < cnt; i++){
    for (int j = 0; j <= Y[i].size(); j++){
      int u = idL[i][j];
      int v = idR[i][j];
      E[u].push_back(v);
      E[v].push_back(u);
    }
  }
  vector<bool> used(V, false);
  used[0] = true;
  queue<int> Q;
  Q.push(0);
  while (!Q.empty()){
    int v = Q.front();
    Q.pop();
    for (int w : E[v]){
      if (!used[w]){
        used[w] = true;
        Q.push(w);
      }
    }
  }
  double ans = 0;
  for (int i = 0; i < cnt - 1; i++){
    for (int j = 1; j < C[i].size(); j++){
      int v = S[i + 1] + j;
      if (!used[v]){
        double l = Y[i][C[i][j].first] - Y[i][C[i][j - 1].first];
        double r = Y[i + 1][C[i][j].second] - Y[i + 1][C[i][j - 1].second];
        ans += (l + r) * (X[i + 1] - X[i]) / 2;
      }
    }
  }
  cout << ans << endl;
}
accuracy: 1
time_ms: 20
memory_kb: 16428
final_rank: 10

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 2;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}



typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	//誤差がisis_lpに比べて大きいので、できるだけisis_lpを使う
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
//bool isis_ss(Line s, Line t) {
//	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
//}
//線分と線分の交差判定2
bool isis_ss(Line s, Line t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
typedef vector<Point> polygon;
polygon ConvexHull(polygon p) {
	int n = p.size();
	int k = 0;
	sort(p.begin(), p.end());
	polygon ch(2 * n);
	for (int i = 0; i < n; ch[k++] = p[i++]) {
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], p[i]) <= 0)--k;
	}
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
		while (k >= t && ccw(ch[k - 2], ch[k - 1], p[i]) <= 0)--k;
	}
	ch.resize(k - 1);
	return ch;
}
ld area(const polygon& p) {
	ld ret = 0;
	int n = p.size();
	rep(j, n)ret += cross(p[j], p[(j + 1) % n]);
	return ret / 2.0;
}

int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

void solve() {
	int n; cin >> n;
	vector<int> x(n), y(n);
	rep(i, n)cin >> x[i] >> y[i];
	vector<Point> vp;
	vector<Point> p(n);
	rep(i, n) {
		p[i] = { (ld)x[i],(ld)y[i] };
		vp.push_back(p[i]);
	}
	rep(i, n - 1)Rep(j, i + 1, n - 1) {
		Line l1 = { p[i],p[i + 1] };
		Line l2 = { p[j],p[j + 1] };
		if (isis_ss(l1, l2)&&isis_ll(l1,l2)) {
			vp.push_back(is_ll(l1, l2));
		}
	}
	vector<Point> nvp;
	rep(i, vp.size()) {
		bool ok = true;
		for (Point p : nvp) {
			if (abs(p - vp[i]) < eps)ok = false;
		}
		if (ok)nvp.push_back(vp[i]);
	}
	swap(vp, nvp);

	int ce = 0;
	set<P> st;
	vector<map<int, int>> nex(vp.size());
	vector<vector<pair<ld,int>>> mem(vp.size());
	rep(i, n - 1) {
		vector<pair<ld, int>> z;
		Line l = { p[i],p[i + 1] };
		rep(j, vp.size()) {
			if (isis_sp(l, vp[j])) {
				ld t = abs(vp[j]-l.a) / abs(l.b - l.a);
				z.push_back({ t,j });
			}
		}
		sort(all(z));
		rep(j, (int)z.size() - 1) {
			int id = z[j].second;
			int to = z[j + 1].second;
			P p = minmax({ id,to });
			if (!st.count(p)) {
				st.insert(p);
				ce++;
				mem[id].push_back({ arg(vp[to] - vp[id]),to });
				mem[to].push_back({ arg(vp[id] - vp[to]),id });
				//cout << id << " " << to << "\n";
			}
		}
	}
	rep(i, vp.size()) {
		sort(all(mem[i]));
		rep(j, mem[i].size()) {
			int nj = j + 1 == mem[i].size() ? 0 : j + 1;
			nex[i][mem[i][j].second] = mem[i][nj].second;
		}
	}
	auto calc = [&](P p) {
		int a = p.first, b = p.second;
		ld dx = real(vp[a]) - real(vp[b]);
		ld dy = imag(vp[a]) + imag(vp[b]);
		return dx * dy / 2.0;
	};
	set<P> used;
	ld ans = 0;
	rep(i, vp.size()) {
		rep(j, mem[i].size()) {
			P cur = { i,mem[i][j].second };
			if (used.count(cur))continue;
			used.insert(cur);
			ld sum = calc(cur);
			while (true) {
				int a = cur.first;
				int b = cur.second;
				int c = nex[b][a];
				P ncur = { b,c };
				if (used.count(ncur)) {
					break;
				}
				else {
					used.insert(ncur);
					cur = ncur;
					sum += calc(cur);
				}
			}
			//cout << sum << "\n";
			if (sum >= 0)ans += sum;
		}
	}
	cout << ans << "\n";
}



signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	//while (cin >> n, n)
		solve();
	return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 5328
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
const double eps = 0.0000001;
const double INF = 1000000;
struct point{
  double x, y;
  point(){
  }
  point(double x, double y): x(x), y(y){
  }
  point operator +(point P){
    return point(x + P.x, y + P.y);
  }
  point operator -(point P){
    return point(x - P.x, y - P.y);
  }
  point operator *(double k){
    return point(x * k, y * k);
  }
  point operator /(double k){
    return point(x / k, y / k);
  }
};
point rotate(point P, double t){
  return point(P.x * cos(t) - P.y * sin(t), P.x * sin(t) + P.y * cos(t));
}
double abs(point P){
  return sqrt(P.x * P.x + P.y * P.y);
}
double dot(point P, point Q){
  return P.x * Q.x + P.y * Q.y;
}
double cross(point P, point Q){
  return P.x * Q.y - P.y * Q.x;
}
struct line{
  point A, B;
  line(){
  }
  line(point A, point B): A(A), B(B){
  }
};
point vec(line L){
  return L.B - L.A;
}
bool point_on_segment(point P, line L){
  return dot(P - L.A, vec(L)) > -eps && dot(P - L.B, vec(L)) < eps;
}
bool is_parallel(line L1, line L2){
  return abs(cross(vec(L1), vec(L2))) <= eps;
}
point line_intersection(line L1, line L2){
  return L1.A + vec(L1) * cross(L2.A - L1.A, vec(L2)) / cross(vec(L1), vec(L2));
}
int main(){
  cout << fixed << setprecision(20);
  int N;
  cin >> N;
  vector<point> P(N);
  for (int i = 0; i < N; i++){
    cin >> P[i].x >> P[i].y;
  }
  for (int i = 0; i < N; i++){
    P[i] = rotate(P[i], 1);
  }
  vector<line> L(N - 1);
  for (int i = 0; i < N - 1; i++){
    L[i] = line(P[i], P[i + 1]);
  }
  vector<double> X;
  X.push_back(-INF);
  X.push_back(INF);
  for (int i = 0; i < N; i++){
    X.push_back(P[i].x);
  }
  for (int i = 0; i < N - 1; i++){
    for (int j = i + 2; j < N - 1; j++){
      if (!is_parallel(L[i], L[j])){
        point A = line_intersection(L[i], L[j]);
        if (point_on_segment(A, L[i]) && point_on_segment(A, L[j])){
          X.push_back(A.x);
        }
      }
    }
  }
  sort(X.begin(), X.end());
  int cnt1 = X.size();
  vector<double> X2;
  X2.push_back(X[0]);
  for (int i = 1; i < cnt1; i++){
    if (X[i] - X[i - 1] > eps){
      X2.push_back(X[i]);
    }
  }
  int cnt = X2.size() - 2;
  vector<vector<double>> ly(cnt + 1), ry(cnt + 1);
  for (int i = 0; i <= cnt; i++){
    ly[i].push_back(-INF);
    ly[i].push_back(INF);
    ry[i].push_back(-INF);
    ry[i].push_back(INF);
  }
  vector<int> a(cnt + 1, 0);
  for (int i = 0; i < N - 1; i++){
    int l = lower_bound(X2.begin(), X2.end(), min(P[i].x, P[i + 1].x) - eps) - X2.begin() - 1;
    int r = lower_bound(X2.begin(), X2.end(), max(P[i].x, P[i + 1].x) - eps) - X2.begin() - 1;
    for (int j = l + 1; j <= r; j++){
      line L1(point(X2[j], 0), point(X2[j], 1));
      ly[j].push_back(line_intersection(L[i], L1).y);
      line L2(point(X2[j + 1], 0), point(X2[j + 1], 1));
      ry[j].push_back(line_intersection(L[i], L2).y);
      a[j]++;
    }
  }
  for (int i = 0; i <= cnt; i++){
    sort(ly[i].begin(), ly[i].end());
    sort(ry[i].begin(), ry[i].end());
  }
  int V = 0;
  vector<vector<int>> id(cnt + 1);
  vector<double> S;
  for (int i = 0; i <= cnt; i++){
    id[i] = vector<int>(a[i] + 1);
    for (int j = 0; j <= a[i]; j++){
      id[i][j] = V;
      V++;
      S.push_back(((ly[i][j + 1] - ly[i][j]) + (ry[i][j + 1] - ry[i][j])) * (X2[i + 1] - X2[i]) / 2);
    }
  }
  vector<vector<int>> E(V);
  for (int i = 1; i <= cnt; i++){
    for (int j = 0; j <= a[i]; j++){
      double d = ly[i][j];
      double u = ly[i][j + 1];
      if (u - d > eps){
        int p = lower_bound(ry[i - 1].begin(), ry[i - 1].end(), d + eps) - ry[i - 1].begin() - 1;
        while (ry[i - 1][p + 1] - ry[i - 1][p] < eps){
          p++;
        }
        E[id[i][j]].push_back(id[i - 1][p]);
        E[id[i - 1][p]].push_back(id[i][j]);
      }
    }
  }
  for (int i = 0; i < cnt; i++){
    for (int j = 0; j <= a[i]; j++){
      double d = ry[i][j];
      double u = ry[i][j + 1];
      if (u - d > eps){
        int p = lower_bound(ly[i + 1].begin(), ly[i + 1].end(), d + eps) - ly[i + 1].begin() - 1;
        while (ly[i + 1][p + 1] - ly[i + 1][p] < eps){
          p++;
        }
        E[id[i][j]].push_back(id[i + 1][p]);
        E[id[i + 1][p]].push_back(id[i][j]);
      }
    }
  }
  vector<bool> used(V, false);
  used[0] = true;
  queue<int> Q;
  Q.push(0);
  while (!Q.empty()){
    int v = Q.front();
    Q.pop();
    for (int w : E[v]){
      if (!used[w]){
        used[w] = true;
        Q.push(w);
      }
    }
  }
  double ans = 0;
  for (int i = 0; i < V; i++){
    if (!used[i]){
      ans += S[i];
    }
  }
  cout << ans << endl;
}
accuracy: 1
time_ms: 20
memory_kb: 18168
final_rank: 11

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
const ll MOD=1000000007;


template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}

namespace Geometry{
    typedef long double D;
    typedef complex<long double> P;
    typedef pair<P,D> C;
    
    const D EPS=1e-9;
    const D PI=asin(1)*2;
    const D INF=1e18;
    
    const static bool comp(const P &p1,const P &p2){return p1.real()==p2.real()?p1.imag()<p2.imag():p1.real()<p2.real();}
    
    static bool comp_y(const P &p1,const P &p2){return p1.imag()==p2.imag()?p1.real()<p2.real():p1.imag()<p2.imag();}
    
    static bool eqls(const P &p1,const P &p2){return abs(p1-p2)<EPS;}
    
    D dot(P p1,P p2){return p1.real()*p2.real()+p1.imag()*p2.imag();}
    
    D cross(P p1,P p2){return p1.real()*p2.imag()-p1.imag()*p2.real();}
    
    P project(P vec,P x){return vec*(x/vec).real();}
    
    P project(P p1,P p2,P x){return p1+project(p2-p1,x-p1);}
    
    P reflect(P vec,P x){return vec*conj(x/vec);}
    
    P reflect(P p1,P p2,P x){return p1+reflect(p2-p1,x-p1);}
    
    bool intersectSL(P p1,P p2,P vec){vec/=abs(vec); p1/=vec; p2/=vec; return (p1.imag()<EPS && p2.imag()>-EPS) || (p1.imag()>-EPS && p2.imag()<EPS);}
    
    bool intersectSL(P p1,P p2,P p3,P p4){return intersectSL(p1-p4,p2-p4,p3-p4);}
    
    bool intersectSS(P p1,P p2,P p3,P p4){return (dot(p2-p1,p3-p1)<-EPS && dot(p2-p1,p4-p1)<-EPS) || (dot(p1-p2,p3-p2)<-EPS && dot(p1-p2,p4-p2)<-EPS)?false:intersectSL(p1,p2,p3,p4) && intersectSL(p3,p4,p1,p2);}
    
    D distLP(P vec,P x){return abs((x/vec).imag())*abs(vec);}
    
    D distLP(P p1,P p2,P x){return distLP(p2-p1,x-p1);}
    
    D distSP(P p1,P p2,P x){return dot(p2-p1,x-p1)<-EPS?abs(x-p1):dot(p1-p2,x-p2)<-EPS?abs(x-p2):distLP(p1,p2,x);}
    
    D distSS(P p1,P p2,P p3,P p4){return intersectSS(p1,p2,p3,p4)?0.0:min(min(distSP(p1,p2,p3),distSP(p1,p2,p4)),min(distSP(p3,p4,p1),distSP(p3,p4,p2)));}
    
    P crosspointLL(P p1,P p2,P vec){return abs(cross(p2-p1,vec))<EPS?vec:vec*cross(p2-p1,p2)/cross(p2-p1,vec);}
    
    P crosspointLL(P p1,P p2,P p3,P p4){return p4+crosspointLL(p1-p4,p2-p4,p3-p4);}
    
    P crosspointSS(P p1,P p2,P p3,P p4){return distSP(p1,p2,p3)<EPS?p3:distSP(p1,p2,p4)<EPS?p4:crosspointLL(p1,p2,p3,p4);}
    
    bool intersectShL(P p1,P p2,P vec){vec/=abs(vec); return intersectSL(p1,p2,vec) && crosspointLL(p1/vec,p2/vec,vec/vec).real()>-EPS;}
    
    bool intersectShL(P p1,P p2,P p3,P p4){return intersectShL(p1-p3,p2-p3,p4-p3);}
    
    //1::in,0::on edge,-1::out
    int contain(const vector<P> &poly,const P &p){
        vector<P> A={{65537,96847},{-24061,6701},{56369,-86509},{-93763,-78049},{56957,10007}};
        vector<bool> cnt(5,false);
        for(int i=1;i<=poly.size();i++){
            if(distSP(poly[i-1],poly[i%poly.size()],p)<EPS){return 0;}
            for(int j=0;j<5;j++){
                if(intersectShL(poly[i-1],poly[i%poly.size()],p,p+A[j])){cnt[j]=!cnt[j];}
            }
        }
        int in=0;
        for(int j=0;j<5;j++){if(cnt[j]){in++;}}
        return in>=3?1:-1;
    }
    
    vector<P> convexcut(const vector<P> &poly,P p1,P p2){
        vector<P> ret;
        for(int i=1;i<=poly.size();i++){
            if(cross(p2-p1,poly[i-1]-p1)>-EPS){ret.push_back(poly[i-1]);}
            if(intersectSL(poly[i-1],poly[i%poly.size()],p1,p2) && distLP(p1,p2,poly[i-1])>EPS && distLP(p1,p2,poly[i%poly.size()])>EPS){ret.push_back(crosspointLL(poly[i-1],poly[i%poly.size()],p1,p2));}
        }
        return ret;
    }
    
    D area(const vector<P> &poly){
        D ans=0;
        for(int i=2;i<poly.size();i++){ans+=cross(poly[i-1]-poly[0],poly[i]-poly[0]);}
        return abs(ans)/2;
    }
    
    vector<P> convexhull(vector<P> pts){
        vector<P> ret;
        sort(pts.begin(),pts.end(),comp);
        for(auto &I:pts){
            if(!ret.empty() && I==ret.back()){continue;}
            while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){ret.pop_back();}
            ret.push_back(I);
        }
        reverse(pts.begin(),pts.end());
        for(auto &I:pts){
            if(!ret.empty() && I==ret.back()){continue;}
            while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){ret.pop_back();}
            ret.push_back(I);
        }
        if(ret[0]==ret.back()){ret.pop_back();}
        return ret;
    }
    
    //4::seperate,3::circumscribe,2::intersect,1::inscribe,0::contain,-1::same
    int intersectCC(C c1,C c2){
        D d=abs(c1.F-c2.F),r=c1.S+c2.S,dif=abs(c2.S-c1.S);
        if(d<EPS && dif<EPS){return -1;}
        if(d-r>EPS){return 4;}
        if(d-r>-EPS){return 3;}
        if(d-dif>EPS){return 2;}
        if(d-dif>-EPS){return 1;}
        return 0;
    }
    
    vector<P> crosspointLC(P p1,P p2,C c){
        vector<P> ret;
        P pr=project(p1,p2,c.F);
        D d=distLP(p1,p2,c.F);
        if(d-c.S>EPS){return ret;}
        if(d-c.S>-EPS){ret.push_back(pr); return ret;}
        P vec=p2-p1; vec*=sqrt(c.S*c.S-d*d)/abs(vec);
        ret.push_back(pr-vec);
        ret.push_back(pr+vec);
        return ret;
    }
    
    vector<P> crosspointSC(P p1,P p2,C c){
        vector<P> ret;
        for(auto &I:crosspointLC(p1,p2,c)){if(distSP(p1,p2,I)<EPS){ret.push_back(I);}}
        return ret;
    }
    
    vector<P> crosspointCC(C c1,C c2){
        vector<P> ret;
        P vec=c2.F-c1.F;
        D base=(c1.S*c1.S+norm(vec)-c2.S*c2.S)/(2*abs(vec));
        D h=sqrt(c1.S*c1.S-base*base);
        vec/=abs(vec);
        ret.push_back(c1.F+vec*P(base,-h));
        ret.push_back(c1.F+vec*P(base,h));
        return ret;
    }
    
    vector<P> tangentCP(C c,P p){return crosspointCC(c,C(p,sqrt(norm(c.F-p)-c.S*c.S)));}
    
    vector<pair<P,P>> tangentCC(C c1,C c2){
        vector<pair<P,P>> ret;
        P d=c2.F-c1.F;
        for(D i:{-1,1}){
            D r=c1.S+c2.S*i;
            if(intersectCC(c1,c2)>i+1){
                for(P s:{-1i,1i}){
                    P p=r+s*sqrt(norm(d)-norm(r));
                    ret.push_back({c1.F+d*c1.S/norm(d)*p,c2.F-d*i*c2.S/norm(d)*p});
                }
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly,C c){
        D ret=0;
        for(int i=0;i<poly.size();i++){
            P a=poly[i]-c.F,b=poly[(i+1)%poly.size()]-c.F;
            if(abs(a)<c.S+EPS && abs(b)<c.S+EPS){ret+=cross(a,b);}
            else{
                vector<P> A=crosspointSC(a,b,{0,c.S});
                if(A.empty()){ret+=c.S*c.S*arg(b/a);}
                else{
                    ret+=(abs(a)<c.S?cross(a,A[0]):c.S*c.S*arg(A[0]/a));
                    ret+=(abs(b)<c.S?cross(A.back(),b):c.S*c.S*arg(b/A.back()));
                    ret+=cross(A[0],A.back());
                }
            }
        }
        return abs(ret)/2;
    }
    
    //反時計回り
    D diameter(const vector<P> &poly){
        D ret=0;
        ll l=0,r=0,n=poly.size();
        if(n==2){return abs(poly[0]-poly[1]);}
        for(int i=0;i<n;i++){
            if(comp(poly[l],poly[i])){l=i;}
            if(comp(poly[i],poly[r])){r=i;}
        }
        ll sl=r,sr=l;
        while(sl!=l || sr!=r){
            ret=max(ret,abs(poly[r]-poly[l]));
            if(cross(poly[(l+1)%n]-poly[l],poly[(r+1)%n]-poly[r])<0){(++l)%=n;}
            else{(++r)%=n;}
        }
        return ret;
    }
    
    D closestpair(vector<P> pt){
        sort(pt.begin(),pt.end(),comp);
        D ret=INF;
        for(ll i=1;i<pt.size();i<<=1){
            for(ll j=0;i+j<pt.size();j+=i*2){
                ll m=i+j;
                vector<P> R;
                D l=-INF,r=INF;
                for(ll k=j;k<m;k++){l=max(l,pt[k].real());}
                for(ll k=0;m+k<pt.size() && k<i;k++){r=min(r,pt[m+k].real());}
                for(ll k=0;m+k<pt.size() && k<i;k++){if(pt[m+k].real()-l<ret){R.push_back(pt[m+k]);}}
                ll idx=0;
                for(ll k=j;k<m;k++){
                    if(r-pt[k].real()>ret){continue;}
                    while(idx<R.size() && pt[k].imag()-R[idx].imag()>ret){idx++;}
                    for(ll n=idx;n<R.size() && R[n].imag()-pt[k].imag()<ret;n++){ret=min(ret,abs(R[n]-pt[k]));}
                }
                inplace_merge(pt.begin()+j,pt.begin()+m,j+i*2<pt.size()?pt.begin()+j+2*i:pt.end(),comp_y);
            }
        }
        return ret;
    }
    
    P centerofgravity(const vector<P> &pt){
        P ret(0,0);
        D wt=0;
        for(int i=2;i<pt.size();i++){
            D w2=cross(pt[i-1]-pt[0],pt[i]-pt[0]);
            P p=(pt[0]+pt[i-1]+pt[i])/(D)3;
            wt+=w2;
            ret+=p*w2;
        }
        return ret/wt;
    }
    
    void segment_arrangement(const vector<pair<P,P>> &L,vector<pair<int,int>> &seg,vector<P> &pt){
        int N=(int)L.size();
        for(int i=0;i<N;i++){
            pt.push_back(L[i].F);
            pt.push_back(L[i].S);
            for(int j=i+1;j<N;j++){
                if(intersectSS(L[i].F,L[i].S,L[j].F,L[j].S)){
                    pt.push_back(crosspointSS(L[i].F,L[i].S,L[j].F,L[j].S));
                }
            }
        }
        auto le=[](P a,P b){return eqls(a,b)?false:comp(a,b);};
        sort(pt.begin(),pt.end(),le);
        pt.erase(unique(pt.begin(),pt.end(),eqls),pt.end());
        for(auto &I:L){
            vector<pair<D,int>> on;
            for(int j=0;j<(int)pt.size();j++){
                if(distSP(I.F,I.S,pt[j])<EPS){
                    on.emplace_back(abs(pt[j]-I.F),j);
                }
            }
            sort(on.begin(),on.end());
            for(int j=1;j<(int)on.size();j++){
                seg.emplace_back(on[j-1].S,on[j].S);
            }
        }
        sort(seg.begin(),seg.end());
        seg.erase(unique(seg.begin(),seg.end()),seg.end());
    }
    
    vector<P> convex_of_segments(const vector<pair<P,P>> &L){
        vector<pair<int,int>> seg;
        vector<P> pt;
        segment_arrangement(L,seg,pt);
        vector<vector<int>> edge(pt.size());
        for(auto &I:seg){
            edge[I.F].push_back(I.S);
            edge[I.S].push_back(I.F);
        }
        vector<P> ret;
        function<void(int,int)> dfs=[&](int v,int pre){
            if(pre!=-1 && v==0){return;}
            ret.push_back(pt[v]);
            vector<pair<D,int>> nx;
            for(auto &u:edge[v]){
                D a=arg((pt[u]-pt[v])/(pre==-1 || eqls(pt[v],pt[pre])?P(1):pt[v]-pt[pre]));
                if(abs(a+PI)<EPS){a=PI;}
                nx.emplace_back(a,u);
            }
            sort(nx.begin(),nx.end());
            dfs(nx[0].S,v);
        };
        dfs(0,-1);
        return ret;
    }
    
    istream & operator >> (istream &i,P &p){D x,y; i>>x>>y; p={x,y}; return i;}
    istream & operator >> (istream &i,C &p){D x,y; i>>x>>y>>p.S; p.F={x,y}; return i;}
};

using namespace Geometry;



int main(){
    ll n;
    cin>>n;
    vector<P> A(n);
    cin>>A;
    vector<pair<P,P>> B(n-1);
    for(int j=1;j<n;j++){B[j-1]={A[j-1],A[j]};}
    cout<<fixed<<setprecision(12)<<area(convex_of_segments(B))<<endl;
    
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3492
final_rank: 2

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
const ll MOD=1000000007;


template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}

namespace Geometry{
    typedef long double D;
    typedef complex<long double> P;
    typedef pair<P,D> C;
    
    const D EPS=1e-9;
    const D PI=asin(1)*2;
    const D INF=1e18;
    
    static bool comp(const P &p1,const P &p2){
        if(p1.real()==p2.real()){return p1.imag()<p2.imag();}
        return p1.real()<p2.real();
    }
    
    static bool comp_y(const P &p1,const P &p2){
        if(p1.imag()==p2.imag()){return p1.real()<p2.real();}
        return p1.imag()<p2.imag();
    }
    
    static bool eqls(const P &p1,const P &p2){return abs(p1-p2)<EPS;}
    
    D dot(P p1,P p2){return p1.real()*p2.real()+p1.imag()*p2.imag();}
    
    D cross(P p1,P p2){return p1.real()*p2.imag()-p1.imag()*p2.real();}
    
    P project(P vec,P x){return vec*(x/vec).real();}
    
    P project(P p1,P p2,P x){return p1+project(p2-p1,x-p1);}
    
    P reflect(P vec,P x){return vec*conj(x/vec);}
    
    P reflect(P p1,P p2,P x){return p1+reflect(p2-p1,x-p1);}
    
    bool intersectSL(P p1,P p2,P vec){
        vec/=abs(vec); p1/=vec; p2/=vec;
        return (p1.imag()<EPS && p2.imag()>-EPS) || (p1.imag()>-EPS && p2.imag()<EPS);
    }
    
    bool intersectSL(P p1,P p2,P p3,P p4){return intersectSL(p1-p4,p2-p4,p3-p4);}
    
    bool intersectSS(P p1,P p2,P p3,P p4){
        if(dot(p2-p1,p3-p1)<-EPS && dot(p2-p1,p4-p1)<-EPS){return false;}
        if(dot(p1-p2,p3-p2)<-EPS && dot(p1-p2,p4-p2)<-EPS){return false;}
        return intersectSL(p1,p2,p3,p4) && intersectSL(p3,p4,p1,p2);
    }
    
    D distLP(P vec,P x){return abs((x/vec).imag())*abs(vec);}
    
    D distLP(P p1,P p2,P x){return distLP(p2-p1,x-p1);}
    
    D distSP(P p1,P p2,P x){
        if(dot(p2-p1,x-p1)<-EPS){return abs(x-p1);}
        if(dot(p1-p2,x-p2)<-EPS){return abs(x-p2);}
        return distLP(p1,p2,x);
    }
    
    D distSS(P p1,P p2,P p3,P p4){
        if(intersectSS(p1,p2,p3,p4)){return 0.0;}
        return min({distSP(p1,p2,p3),distSP(p1,p2,p4),
            distSP(p3,p4,p1),distSP(p3,p4,p2)});
    }
    
    P crosspointLL(P p1,P p2,P vec){
        if(abs(cross(p2-p1,vec))<EPS){return vec;}
        return vec*cross(p2-p1,p2)/cross(p2-p1,vec);
    }
    
    P crosspointLL(P p1,P p2,P p3,P p4){
        return p4+crosspointLL(p1-p4,p2-p4,p3-p4);
    }
    
    P crosspointSS(P p1,P p2,P p3,P p4){
        if(distSP(p1,p2,p3)<EPS){return p3;}
        if(distSP(p1,p2,p4)<EPS){return p4;}
        return crosspointLL(p1,p2,p3,p4);
    }
    
    bool intersectShL(P p1,P p2,P vec){
        vec/=abs(vec);
        return intersectSL(p1,p2,vec) &&
        crosspointLL(p1/vec,p2/vec,vec/vec).real()>-EPS;
    }
    
    bool intersectShL(P p1,P p2,P p3,P p4){
        return intersectShL(p1-p3,p2-p3,p4-p3);
    }
    
    //1::in,0::on edge,-1::out
    int contain(const vector<P> &poly,const P &p){
        vector<P> A={{65537,96847},{-24061,6701},{56369,-86509},{-93763,-78049},{56957,10007}};
        int s=A.size();
        vector<bool> cnt(s,false);
        for(int i=0;i<(int)poly.size();i++){
            int k=(i+1)%poly.size();
            if(distSP(poly[i],poly[k],p)<EPS){return 0;}
            for(int j=0;j<s;j++){
                if(intersectShL(poly[i],poly[k],p,p+A[j])){cnt[j]=!cnt[j];}
            }
        }
        int in=0;
        for(int j=0;j<s;j++){if(cnt[j]){in++;}}
        return in>s/2?1:-1;
    }
    
    vector<P> convexcut(const vector<P> &poly,P p1,P p2){
        vector<P> ret;
        for(int i=0;i<(int)poly.size();i++){
            int j=(i+1)%poly.size();
            if(cross(p2-p1,poly[i]-p1)>-EPS){ret.push_back(poly[i]);}
            if(intersectSL(poly[i],poly[j],p1,p2) &&
               distLP(p1,p2,poly[i])>EPS && distLP(p1,p2,poly[j])>EPS){
                ret.push_back(crosspointLL(poly[i],poly[j],p1,p2));
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly){
        D ans=0;
        for(int i=2;i<(int)poly.size();i++){
            ans+=cross(poly[i-1]-poly[0],poly[i]-poly[0]);
        }
        return abs(ans)/2;
    }
    
    vector<P> convexhull(vector<P> pts){
        vector<P> ret;
        sort(pts.begin(),pts.end(),comp);
        auto fnc=[&](){
            for(auto &I:pts){
                if(!ret.empty() && I==ret.back()){continue;}
                while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){
                    ret.pop_back();
                }
                ret.push_back(I);
            }
        };
        fnc();
        reverse(pts.begin(),pts.end());
        fnc();
        if(ret[0]==ret.back()){ret.pop_back();}
        return ret;
    }
    
    //4::seperate,3::circumscribe,2::intersect,1::inscribe,0::contain,-1::same
    int intersectCC(C c1,C c2){
        D d=abs(c1.F-c2.F),r=c1.S+c2.S,dif=abs(c2.S-c1.S);
        if(d<EPS && dif<EPS){return -1;}
        if(d-r>EPS){return 4;}
        if(d-r>-EPS){return 3;}
        if(d-dif>EPS){return 2;}
        if(d-dif>-EPS){return 1;}
        return 0;
    }
    
    vector<P> crosspointLC(P p1,P p2,C c){
        vector<P> ret;
        P pr=project(p1,p2,c.F);
        D d=distLP(p1,p2,c.F);
        if(d-c.S>EPS){return ret;}
        if(d-c.S>-EPS){ret.push_back(pr); return ret;}
        P vec=p2-p1; vec*=sqrt(c.S*c.S-d*d)/abs(vec);
        ret.push_back(pr-vec);
        ret.push_back(pr+vec);
        return ret;
    }
    
    vector<P> crosspointSC(P p1,P p2,C c){
        vector<P> ret;
        for(auto &I:crosspointLC(p1,p2,c)){
            if(distSP(p1,p2,I)<EPS){ret.push_back(I);}
        }
        return ret;
    }
    
    vector<P> crosspointCC(C c1,C c2){
        vector<P> ret;
        P vec=c2.F-c1.F;
        D base=(c1.S*c1.S+norm(vec)-c2.S*c2.S)/(2*abs(vec));
        D h=sqrt(c1.S*c1.S-base*base);
        vec/=abs(vec);
        ret.push_back(c1.F+vec*P(base,-h));
        ret.push_back(c1.F+vec*P(base,h));
        return ret;
    }
    
    vector<P> tangentCP(C c,P p){
        return crosspointCC(c,C(p,sqrt(norm(c.F-p)-c.S*c.S)));
    }
    
    vector<pair<P,P>> tangentCC(C c1,C c2){
        vector<pair<P,P>> ret;
        P d=c2.F-c1.F;
        for(D i:{-1,1}){
            D r=c1.S+c2.S*i;
            if(intersectCC(c1,c2)>i+1){
                for(P s:{-1i,1i}){
                    P p=r+s*sqrt(norm(d)-norm(r));
                    ret.push_back({c1.F+d*c1.S/norm(d)*p,c2.F-d*i*c2.S/norm(d)*p});
                }
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly,C c){
        D ret=0;
        for(int i=0;i<(int)poly.size();i++){
            P a=poly[i]-c.F,b=poly[(i+1)%poly.size()]-c.F;
            if(abs(a)<c.S+EPS && abs(b)<c.S+EPS){ret+=cross(a,b);}
            else{
                vector<P> A=crosspointSC(a,b,{0,c.S});
                if(A.empty()){ret+=c.S*c.S*arg(b/a);}
                else{
                    ret+=(abs(a)<c.S?cross(a,A[0]):c.S*c.S*arg(A[0]/a));
                    ret+=(abs(b)<c.S?cross(A.back(),b):c.S*c.S*arg(b/A.back()));
                    ret+=cross(A[0],A.back());
                }
            }
        }
        return abs(ret)/2;
    }
    
    //反時計回り
    D diameter(const vector<P> &poly){
        D ret=0;
        ll l=0,r=0,n=poly.size();
        if(n==2){return abs(poly[0]-poly[1]);}
        for(int i=0;i<n;i++){
            if(comp(poly[l],poly[i])){l=i;}
            if(comp(poly[i],poly[r])){r=i;}
        }
        ll sl=r,sr=l;
        while(sl!=l || sr!=r){
            ret=max(ret,abs(poly[r]-poly[l]));
            if(cross(poly[(l+1)%n]-poly[l],poly[(r+1)%n]-poly[r])<0){(++l)%=n;}
            else{(++r)%=n;}
        }
        return ret;
    }
    
    D closestpair(vector<P> pt){
        sort(pt.begin(),pt.end(),comp);
        D ret=INF;
        int N=pt.size();
        for(int i=1;i<N;i<<=1){
            for(int j=0;i+j<N;j+=i*2){
                int m=i+j;
                vector<P> R;
                D l=-INF,r=INF;
                for(int k=j;k<m;k++){l=max(l,pt[k].real());}
                for(int k=0;m+k<N && k<i;k++){r=min(r,pt[m+k].real());}
                for(int k=0;m+k<N && k<i;k++){
                    if(pt[m+k].real()-l<ret){R.push_back(pt[m+k]);}
                }
                int idx=0;
                for(int k=j;k<m;k++){
                    if(r-pt[k].real()>ret){continue;}
                    int M=R.size();
                    while(idx<M && pt[k].imag()-R[idx].imag()>ret){idx++;}
                    for(int s=idx;s<M && R[s].imag()-pt[k].imag()<ret;s++){
                        ret=min(ret,abs(R[s]-pt[k]));
                    }
                }
                auto ed=(j+i*2<N?pt.begin()+j+2*i:pt.end());
                inplace_merge(pt.begin()+j,pt.begin()+m,ed,comp_y);
            }
        }
        return ret;
    }
    
    P centerofgravity(const vector<P> &pt){
        P ret(0,0);
        D wt=0;
        for(int i=2;i<(int)pt.size();i++){
            D w2=cross(pt[i-1]-pt[0],pt[i]-pt[0]);
            P p=(pt[0]+pt[i-1]+pt[i])/(D)3;
            wt+=w2;
            ret+=p*w2;
        }
        return ret/wt;
    }
    
    void segment_arrangement(const vector<pair<P,P>> &L,vector<pair<int,int>> &seg,vector<P> &pt){
        int N=(int)L.size();
        for(int i=0;i<N;i++){
            pt.push_back(L[i].F);
            pt.push_back(L[i].S);
            for(int j=i+1;j<N;j++){
                if(intersectSS(L[i].F,L[i].S,L[j].F,L[j].S)){
                    pt.push_back(crosspointSS(L[i].F,L[i].S,L[j].F,L[j].S));
                }
            }
        }
        auto le=[](P a,P b){return eqls(a,b)?false:comp(a,b);};
        sort(pt.begin(),pt.end(),le);
        pt.erase(unique(pt.begin(),pt.end(),eqls),pt.end());
        for(auto &I:L){
            vector<pair<D,int>> on;
            for(int j=0;j<(int)pt.size();j++){
                if(distSP(I.F,I.S,pt[j])<EPS){
                    on.emplace_back(abs(pt[j]-I.F),j);
                }
            }
            sort(on.begin(),on.end());
            for(int j=1;j<(int)on.size();j++){
                seg.emplace_back(on[j-1].S,on[j].S);
            }
        }
        sort(seg.begin(),seg.end());
        seg.erase(unique(seg.begin(),seg.end()),seg.end());
    }
    
    vector<P> convex_of_segments(const vector<pair<P,P>> &L){
        vector<pair<int,int>> seg;
        vector<P> pt;
        segment_arrangement(L,seg,pt);
        vector<vector<int>> edge(pt.size());
        for(auto &I:seg){
            edge[I.F].push_back(I.S);
            edge[I.S].push_back(I.F);
        }
        vector<P> ret;
        function<void(int,int)> dfs=[&](int v,int pre){
            if(pre!=-1 && v==0){return;}
            ret.push_back(pt[v]);
            vector<pair<D,int>> nx;
            for(auto &u:edge[v]){
                D a=arg((pt[u]-pt[v])/(pre==-1 || eqls(pt[v],pt[pre])?P(1):pt[v]-pt[pre]));
                if(abs(a+PI)<EPS){a=PI;}
                nx.emplace_back(a,u);
            }
            sort(nx.begin(),nx.end());
            dfs(nx[0].S,v);
        };
        dfs(0,-1);
        return ret;
    }
    
    istream & operator >> (istream &i,P &p){D x,y; i>>x>>y; p={x,y}; return i;}
    istream & operator >> (istream &i,C &p){D x,y; i>>x>>y>>p.S; p.F={x,y}; return i;}
};

using namespace Geometry;



int main(){
    
    ll n;
    cin>>n;
    vector<P> A(n);
    cin>>A;
    vector<pair<P,P>> B(n-1);
    for(int j=1;j<n;j++){B[j-1]={A[j-1],A[j]};}
    cout<<fixed<<setprecision(12)<<area(convex_of_segments(B))<<endl;
    
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3492
final_rank: 2

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
const ll MOD=1000000007;


template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}

namespace Geometry{
    typedef long double D;
    typedef complex<long double> P;
    typedef pair<P,D> C;
    
    const D EPS=1e-9;
    const D PI=asin(1)*2;
    const D INF=1e18;
    
    static bool comp(const P &p1,const P &p2){
        if(p1.real()==p2.real()){return p1.imag()<p2.imag();}
        return p1.real()<p2.real();
    }
    
    static bool comp_y(const P &p1,const P &p2){
        if(p1.imag()==p2.imag()){return p1.real()<p2.real();}
        return p1.imag()<p2.imag();
    }
    
    D dot(P p1,P p2){return p1.real()*p2.real()+p1.imag()*p2.imag();}
    
    D cross(P p1,P p2){return p1.real()*p2.imag()-p1.imag()*p2.real();}
    
    P project(P vec,P x){return vec*(x/vec).real();}
    
    P project(P p1,P p2,P x){return p1+project(p2-p1,x-p1);}
    
    P reflect(P vec,P x){return vec*conj(x/vec);}
    
    P reflect(P p1,P p2,P x){return p1+reflect(p2-p1,x-p1);}
    
    bool intersectSL(P p1,P p2,P vec){
        vec/=abs(vec); p1/=vec; p2/=vec;
        return (p1.imag()<EPS && p2.imag()>-EPS) || (p1.imag()>-EPS && p2.imag()<EPS);
    }
    
    bool intersectSL(P p1,P p2,P p3,P p4){return intersectSL(p1-p4,p2-p4,p3-p4);}
    
    bool intersectSS(P p1,P p2,P p3,P p4){
        if(dot(p2-p1,p3-p1)<-EPS && dot(p2-p1,p4-p1)<-EPS){return false;}
        if(dot(p1-p2,p3-p2)<-EPS && dot(p1-p2,p4-p2)<-EPS){return false;}
        return intersectSL(p1,p2,p3,p4) && intersectSL(p3,p4,p1,p2);
    }
    
    D distLP(P vec,P x){return abs((x/vec).imag())*abs(vec);}
    
    D distLP(P p1,P p2,P x){return distLP(p2-p1,x-p1);}
    
    D distSP(P p1,P p2,P x){
        if(dot(p2-p1,x-p1)<-EPS){return abs(x-p1);}
        if(dot(p1-p2,x-p2)<-EPS){return abs(x-p2);}
        return distLP(p1,p2,x);
    }
    
    D distSS(P p1,P p2,P p3,P p4){
        if(intersectSS(p1,p2,p3,p4)){return 0.0;}
        return min({distSP(p1,p2,p3),distSP(p1,p2,p4),
            distSP(p3,p4,p1),distSP(p3,p4,p2)});
    }
    
    P crosspointLL(P p1,P p2,P vec){
        if(abs(cross(p2-p1,vec))<EPS){return vec;}
        return vec*cross(p2-p1,p2)/cross(p2-p1,vec);
    }
    
    P crosspointLL(P p1,P p2,P p3,P p4){
        return p4+crosspointLL(p1-p4,p2-p4,p3-p4);
    }
    
    P crosspointSS(P p1,P p2,P p3,P p4){
        if(distSP(p1,p2,p3)<EPS){return p3;}
        if(distSP(p1,p2,p4)<EPS){return p4;}
        return crosspointLL(p1,p2,p3,p4);
    }
    
    bool intersectShL(P p1,P p2,P vec){
        vec/=abs(vec);
        return intersectSL(p1,p2,vec) &&
        crosspointLL(p1/vec,p2/vec,vec/vec).real()>-EPS;
    }
    
    bool intersectShL(P p1,P p2,P p3,P p4){
        return intersectShL(p1-p3,p2-p3,p4-p3);
    }
    
    //1::in,0::on edge,-1::out
    int contain(const vector<P> &poly,const P &p){
        vector<P> A={{65537,96847},{-24061,6701},{56369,-86509},{-93763,-78049},{56957,10007}};
        int s=A.size();
        vector<bool> cnt(s,false);
        for(int i=0;i<(int)poly.size();i++){
            int k=(i+1)%poly.size();
            if(distSP(poly[i],poly[k],p)<EPS){return 0;}
            for(int j=0;j<s;j++){
                if(intersectShL(poly[i],poly[k],p,p+A[j])){cnt[j]=!cnt[j];}
            }
        }
        int in=0;
        for(int j=0;j<s;j++){if(cnt[j]){in++;}}
        return in>s/2?1:-1;
    }
    
    vector<P> convexcut(const vector<P> &poly,P p1,P p2){
        vector<P> ret;
        for(int i=0;i<(int)poly.size();i++){
            int j=(i+1)%poly.size();
            if(cross(p2-p1,poly[i]-p1)>-EPS){ret.push_back(poly[i]);}
            if(intersectSL(poly[i],poly[j],p1,p2) &&
               distLP(p1,p2,poly[i])>EPS && distLP(p1,p2,poly[j])>EPS){
                ret.push_back(crosspointLL(poly[i],poly[j],p1,p2));
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly){
        D ans=0;
        for(int i=2;i<(int)poly.size();i++){
            ans+=cross(poly[i-1]-poly[0],poly[i]-poly[0]);
        }
        return abs(ans)/2;
    }
    
    vector<P> convexhull(vector<P> pts){
        vector<P> ret;
        sort(pts.begin(),pts.end(),comp);
        auto fnc=[&](){
            for(auto &I:pts){
                if(!ret.empty() && I==ret.back()){continue;}
                while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){
                    ret.pop_back();
                }
                ret.push_back(I);
            }
        };
        fnc();
        reverse(pts.begin(),pts.end());
        fnc();
        if(ret[0]==ret.back()){ret.pop_back();}
        return ret;
    }
    
    //4::seperate,3::circumscribe,2::intersect,1::inscribe,0::contain,-1::same
    int intersectCC(C c1,C c2){
        D d=abs(c1.F-c2.F),r=c1.S+c2.S,dif=abs(c2.S-c1.S);
        if(d<EPS && dif<EPS){return -1;}
        if(d-r>EPS){return 4;}
        if(d-r>-EPS){return 3;}
        if(d-dif>EPS){return 2;}
        if(d-dif>-EPS){return 1;}
        return 0;
    }
    
    vector<P> crosspointLC(P p1,P p2,C c){
        vector<P> ret;
        P pr=project(p1,p2,c.F);
        D d=distLP(p1,p2,c.F);
        if(d-c.S>EPS){return ret;}
        if(d-c.S>-EPS){ret.push_back(pr); return ret;}
        P vec=p2-p1; vec*=sqrt(c.S*c.S-d*d)/abs(vec);
        ret.push_back(pr-vec);
        ret.push_back(pr+vec);
        return ret;
    }
    
    vector<P> crosspointSC(P p1,P p2,C c){
        vector<P> ret;
        for(auto &I:crosspointLC(p1,p2,c)){
            if(distSP(p1,p2,I)<EPS){ret.push_back(I);}
        }
        return ret;
    }
    
    vector<P> crosspointCC(C c1,C c2){
        vector<P> ret;
        P vec=c2.F-c1.F;
        D base=(c1.S*c1.S+norm(vec)-c2.S*c2.S)/(2*abs(vec));
        D h=sqrt(c1.S*c1.S-base*base);
        vec/=abs(vec);
        ret.push_back(c1.F+vec*P(base,-h));
        ret.push_back(c1.F+vec*P(base,h));
        return ret;
    }
    
    vector<P> tangentCP(C c,P p){
        return crosspointCC(c,C(p,sqrt(norm(c.F-p)-c.S*c.S)));
    }
    
    vector<pair<P,P>> tangentCC(C c1,C c2){
        vector<pair<P,P>> ret;
        P d=c2.F-c1.F;
        for(D i:{-1,1}){
            D r=c1.S+c2.S*i;
            if(intersectCC(c1,c2)>i+1){
                for(P s:{-1i,1i}){
                    P p=r+s*sqrt(norm(d)-norm(r));
                    ret.push_back({c1.F+d*c1.S/norm(d)*p,c2.F-d*i*c2.S/norm(d)*p});
                }
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly,C c){
        D ret=0;
        for(int i=0;i<(int)poly.size();i++){
            P a=poly[i]-c.F,b=poly[(i+1)%poly.size()]-c.F;
            if(abs(a)<c.S+EPS && abs(b)<c.S+EPS){ret+=cross(a,b);}
            else{
                vector<P> A=crosspointSC(a,b,{0,c.S});
                if(A.empty()){ret+=c.S*c.S*arg(b/a);}
                else{
                    ret+=(abs(a)<c.S?cross(a,A[0]):c.S*c.S*arg(A[0]/a));
                    ret+=(abs(b)<c.S?cross(A.back(),b):c.S*c.S*arg(b/A.back()));
                    ret+=cross(A[0],A.back());
                }
            }
        }
        return abs(ret)/2;
    }
    
    //反時計回り
    D diameter(const vector<P> &poly){
        D ret=0;
        ll l=0,r=0,n=poly.size();
        if(n==2){return abs(poly[0]-poly[1]);}
        for(int i=0;i<n;i++){
            if(comp(poly[l],poly[i])){l=i;}
            if(comp(poly[i],poly[r])){r=i;}
        }
        ll sl=r,sr=l;
        while(sl!=l || sr!=r){
            ret=max(ret,abs(poly[r]-poly[l]));
            if(cross(poly[(l+1)%n]-poly[l],poly[(r+1)%n]-poly[r])<0){(++l)%=n;}
            else{(++r)%=n;}
        }
        return ret;
    }
    
    D closestpair(vector<P> pt){
        sort(pt.begin(),pt.end(),comp);
        D ret=INF;
        int N=pt.size();
        for(int i=1;i<N;i<<=1){
            for(int j=0;i+j<N;j+=i*2){
                int m=i+j;
                vector<P> R;
                D l=-INF,r=INF;
                for(int k=j;k<m;k++){l=max(l,pt[k].real());}
                for(int k=0;m+k<N && k<i;k++){r=min(r,pt[m+k].real());}
                for(int k=0;m+k<N && k<i;k++){
                    if(pt[m+k].real()-l<ret){R.push_back(pt[m+k]);}
                }
                int idx=0;
                for(int k=j;k<m;k++){
                    if(r-pt[k].real()>ret){continue;}
                    int M=R.size();
                    while(idx<M && pt[k].imag()-R[idx].imag()>ret){idx++;}
                    for(int s=idx;s<M && R[s].imag()-pt[k].imag()<ret;s++){
                        ret=min(ret,abs(R[s]-pt[k]));
                    }
                }
                auto ed=(j+i*2<N?pt.begin()+j+2*i:pt.end());
                inplace_merge(pt.begin()+j,pt.begin()+m,ed,comp_y);
            }
        }
        return ret;
    }
    
    P centerofgravity(const vector<P> &pt){
        P ret(0,0);
        D wt=0;
        for(int i=2;i<(int)pt.size();i++){
            D w2=cross(pt[i-1]-pt[0],pt[i]-pt[0]);
            P p=(pt[0]+pt[i-1]+pt[i])/(D)3;
            wt+=w2;
            ret+=p*w2;
        }
        return ret/wt;
    }
    
    void segment_arrangement(const vector<pair<P,P>> &L,vector<pair<int,int>> &seg,vector<P> &pt){
        int N=(int)L.size();
        for(int i=0;i<N;i++){
            pt.push_back(L[i].F);
            pt.push_back(L[i].S);
            for(int j=i+1;j<N;j++){
                if(intersectSS(L[i].F,L[i].S,L[j].F,L[j].S)){
                    pt.push_back(crosspointSS(L[i].F,L[i].S,L[j].F,L[j].S));
                }
            }
        }
        auto less=[](P a,P b){return abs(a-b)<EPS?false:comp(a,b);};
        sort(pt.begin(),pt.end(),less);
        pt.erase(unique(pt.begin(),pt.end(),[](P a,P b){return abs(a-b)<EPS;}),pt.end());
        for(auto &I:L){
            vector<pair<D,int>> on;
            for(int j=0;j<(int)pt.size();j++){
                if(distSP(I.F,I.S,pt[j])<EPS){
                    on.emplace_back(abs(pt[j]-I.F),j);
                }
            }
            sort(on.begin(),on.end());
            for(int j=1;j<(int)on.size();j++){
                seg.emplace_back(on[j-1].S,on[j].S);
            }
        }
        sort(seg.begin(),seg.end());
        seg.erase(unique(seg.begin(),seg.end()),seg.end());
    }
    
    vector<P> convex_of_segments(const vector<pair<P,P>> &L){
        vector<pair<int,int>> seg;
        vector<P> pt;
        segment_arrangement(L,seg,pt);
        vector<vector<int>> edge(pt.size());
        for(auto &I:seg){
            edge[I.F].push_back(I.S);
            edge[I.S].push_back(I.F);
        }
        vector<P> ret;
        function<void(int,int)> dfs=[&](int v,int pre){
            if(pre!=-1 && v==0){return;}
            ret.push_back(pt[v]);
            vector<pair<D,int>> nx;
            for(auto &u:edge[v]){
                D a=arg((pt[u]-pt[v])/(pre==-1 || abs(pt[v]-pt[pre])<EPS?P(1):pt[v]-pt[pre]));
                if(abs(a+PI)<EPS){a=PI;}
                nx.emplace_back(a,u);
            }
            sort(nx.begin(),nx.end());
            dfs(nx[0].S,v);
        };
        dfs(0,-1);
        return ret;
    }
    
    istream & operator >> (istream &i,P &p){D x,y; i>>x>>y; p={x,y}; return i;}
    istream & operator >> (istream &i,C &p){D x,y; i>>x>>y>>p.S; p.F={x,y}; return i;}
};

using namespace Geometry;


int main(){
    ll n;
    cin>>n;
    vector<P> A(n);
    cin>>A;
    vector<pair<P,P>> B(n-1);
    for(int j=1;j<n;j++){B[j-1]={A[j-1],A[j]};}
    cout<<fixed<<setprecision(12)<<area(convex_of_segments(B))<<endl;
    
    
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3504
final_rank: 5

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
const ll MOD=1000000007;


template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}

namespace Geometry{
    typedef long double D;
    typedef complex<long double> P;
    typedef pair<P,D> C;
    
    const D EPS=1e-9;
    const D PI=asin(1)*2;
    const D INF=1e18;
    
    const static bool comp(const P &p1,const P &p2){return p1.real()==p2.real()?p1.imag()<p2.imag():p1.real()<p2.real();}
    
    D dot(P p1,P p2){return p1.real()*p2.real()+p1.imag()*p2.imag();}
    
    D cross(P p1,P p2){return p1.real()*p2.imag()-p1.imag()*p2.real();}
    
    P project(P vec,P x){return vec*(x/vec).real();}
    
    P project(P p1,P p2,P x){return p1+project(p2-p1,x-p1);}
    
    P reflect(P vec,P x){return vec*conj(x/vec);}
    
    P reflect(P p1,P p2,P x){return p1+reflect(p2-p1,x-p1);}
    
    bool intersectSL(P p1,P p2,P vec){vec/=abs(vec); p1/=vec; p2/=vec; return (p1.imag()<EPS && p2.imag()>-EPS) || (p1.imag()>-EPS && p2.imag()<EPS);}
    
    bool intersectSL(P p1,P p2,P p3,P p4){return intersectSL(p1-p4,p2-p4,p3-p4);}
    
    bool intersectSS(P p1,P p2,P p3,P p4){return (dot(p2-p1,p3-p1)<-EPS && dot(p2-p1,p4-p1)<-EPS) || (dot(p1-p2,p3-p2)<-EPS && dot(p1-p2,p4-p2)<-EPS)?false:intersectSL(p1,p2,p3,p4) && intersectSL(p3,p4,p1,p2);}
    
    D distLP(P vec,P x){return abs((x/vec).imag())*abs(vec);}
    
    D distLP(P p1,P p2,P x){return distLP(p2-p1,x-p1);}
    
    D distSP(P p1,P p2,P x){return dot(p2-p1,x-p1)<-EPS?abs(x-p1):dot(p1-p2,x-p2)<-EPS?abs(x-p2):distLP(p1,p2,x);}
    
    D distSS(P p1,P p2,P p3,P p4){return intersectSS(p1,p2,p3,p4)?0.0:min(min(distSP(p1,p2,p3),distSP(p1,p2,p4)),min(distSP(p3,p4,p1),distSP(p3,p4,p2)));}
    
    P crosspointLL(P p1,P p2,P vec){return abs(cross(p2-p1,vec))<EPS?vec:vec*cross(p2-p1,p2)/cross(p2-p1,vec);}
    
    P crosspointLL(P p1,P p2,P p3,P p4){return p4+crosspointLL(p1-p4,p2-p4,p3-p4);}
    
    P crosspointSS(P p1,P p2,P p3,P p4){return distSP(p1,p2,p3)<EPS?p3:distSP(p1,p2,p4)<EPS?p4:crosspointLL(p1,p2,p3,p4);}
    
    bool intersectShL(P p1,P p2,P vec){vec/=abs(vec); return intersectSL(p1,p2,vec) && crosspointLL(p1/vec,p2/vec,vec/vec).real()>-EPS;}
    
    bool intersectShL(P p1,P p2,P p3,P p4){return intersectShL(p1-p3,p2-p3,p4-p3);}
    
    //1::in,0::on edge,-1::out
    int contain(const vector<P> &poly,const P &p){
        vector<P> A={{65537,96847},{-24061,6701},{56369,-86509},{-93763,-78049},{56957,10007}};
        vector<bool> cnt(5,false);
        for(int i=1;i<=poly.size();i++){
            if(distSP(poly[i-1],poly[i%poly.size()],p)<EPS){return 0;}
            for(int j=0;j<5;j++){
                if(intersectShL(poly[i-1],poly[i%poly.size()],p,p+A[j])){cnt[j]=!cnt[j];}
            }
        }
        int in=0;
        for(int j=0;j<5;j++){if(cnt[j]){in++;}}
        return in>=3?1:-1;
    }
    
    vector<P> convexcut(const vector<P> &poly,P p1,P p2){
        vector<P> ret;
        for(int i=1;i<=poly.size();i++){
            if(cross(p2-p1,poly[i-1]-p1)>-EPS){ret.push_back(poly[i-1]);}
            if(intersectSL(poly[i-1],poly[i%poly.size()],p1,p2) && distLP(p1,p2,poly[i-1])>EPS && distLP(p1,p2,poly[i%poly.size()])>EPS){ret.push_back(crosspointLL(poly[i-1],poly[i%poly.size()],p1,p2));}
        }
        return ret;
    }
    
    D area(const vector<P> &poly){
        D ans=0;
        for(int i=2;i<poly.size();i++){ans+=cross(poly[i-1]-poly[0],poly[i]-poly[0]);}
        return abs(ans)/2;
    }
    
    vector<P> convexhull(vector<P> pts){
        vector<P> ret;
        sort(pts.begin(),pts.end(),comp);
        for(auto &I:pts){
            if(!ret.empty() && I==ret.back()){continue;}
            while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){ret.pop_back();}
            ret.push_back(I);
        }
        reverse(pts.begin(),pts.end());
        for(auto &I:pts){
            if(!ret.empty() && I==ret.back()){continue;}
            while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){ret.pop_back();}
            ret.push_back(I);
        }
        if(ret[0]==ret.back()){ret.pop_back();}
        return ret;
    }
    
    //4::seperate,3::circumscribe,2::intersect,1::inscribe,0::contain,-1::same
    int intersectCC(C c1,C c2){
        D d=abs(c1.F-c2.F),r=c1.S+c2.S,dif=abs(c2.S-c1.S);
        if(d<EPS && dif<EPS){return -1;}
        if(d-r>EPS){return 4;}
        if(d-r>-EPS){return 3;}
        if(d-dif>EPS){return 2;}
        if(d-dif>-EPS){return 1;}
        return 0;
    }
    
    vector<P> crosspointLC(P p1,P p2,C c){
        vector<P> ret;
        P pr=project(p1,p2,c.F);
        D d=distLP(p1,p2,c.F);
        if(d-c.S>EPS){return ret;}
        if(d-c.S>-EPS){ret.push_back(pr); return ret;}
        P vec=p2-p1; vec*=sqrt(c.S*c.S-d*d)/abs(vec);
        ret.push_back(pr-vec);
        ret.push_back(pr+vec);
        return ret;
    }
    
    vector<P> crosspointSC(P p1,P p2,C c){
        vector<P> ret;
        for(auto &I:crosspointLC(p1,p2,c)){if(distSP(p1,p2,I)<EPS){ret.push_back(I);}}
        return ret;
    }
    
    vector<P> crosspointCC(C c1,C c2){
        vector<P> ret;
        P vec=c2.F-c1.F;
        D base=(c1.S*c1.S+norm(vec)-c2.S*c2.S)/(2*abs(vec));
        D h=sqrt(c1.S*c1.S-base*base);
        vec/=abs(vec);
        ret.push_back(c1.F+vec*P(base,-h));
        ret.push_back(c1.F+vec*P(base,h));
        return ret;
    }
    
    vector<P> tangentCP(C c,P p){return crosspointCC(c,C(p,sqrt(norm(c.F-p)-c.S*c.S)));}
    
    vector<pair<P,P>> tangentCC(C c1,C c2){
        vector<pair<P,P>> ret;
        P d=c2.F-c1.F;
        for(D i:{-1,1}){
            D r=c1.S+c2.S*i;
            if(intersectCC(c1,c2)>i+1){
                for(P s:{-1i,1i}){
                    P p=r+s*sqrt(norm(d)-norm(r));
                    ret.push_back({c1.F+d*c1.S/norm(d)*p,c2.F-d*i*c2.S/norm(d)*p});
                }
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly,C c){
        D ret=0;
        for(int i=0;i<poly.size();i++){
            P a=poly[i]-c.F,b=poly[(i+1)%poly.size()]-c.F;
            if(abs(a)<c.S+EPS && abs(b)<c.S+EPS){ret+=cross(a,b);}
            else{
                vector<P> A=crosspointSC(a,b,{0,c.S});
                if(A.empty()){ret+=c.S*c.S*arg(b/a);}
                else{
                    ret+=(abs(a)<c.S?cross(a,A[0]):c.S*c.S*arg(A[0]/a));
                    ret+=(abs(b)<c.S?cross(A.back(),b):c.S*c.S*arg(b/A.back()));
                    ret+=cross(A[0],A.back());
                }
            }
        }
        return abs(ret)/2;
    }
    
    //反時計回り
    D diameter(const vector<P> &poly){
        D ret=0;
        ll l=0,r=0,n=poly.size();
        if(n==2){return abs(poly[0]-poly[1]);}
        for(int i=0;i<n;i++){
            if(comp(poly[l],poly[i])){l=i;}
            if(comp(poly[i],poly[r])){r=i;}
        }
        ll sl=r,sr=l;
        while(sl!=l || sr!=r){
            ret=max(ret,abs(poly[r]-poly[l]));
            if(cross(poly[(l+1)%n]-poly[l],poly[(r+1)%n]-poly[r])<0){(++l)%=n;}
            else{(++r)%=n;}
        }
        return ret;
    }
    
    D closestpair(vector<P> pt){
        sort(pt.begin(),pt.end(),comp);
        D ret=INF;
        for(ll i=1;i<pt.size();i<<=1){
            for(ll j=0;i+j<pt.size();j+=i*2){
                ll m=i+j;
                vector<P> R;
                D l=-INF,r=INF;
                for(ll k=j;k<m;k++){l=max(l,pt[k].real());}
                for(ll k=0;m+k<pt.size() && k<i;k++){r=min(r,pt[m+k].real());}
                for(ll k=0;m+k<pt.size() && k<i;k++){if(pt[m+k].real()-l<ret){R.push_back(pt[m+k]);}}
                ll idx=0;
                for(ll k=j;k<m;k++){
                    if(r-pt[k].real()>ret){continue;}
                    while(idx<R.size() && pt[k].imag()-R[idx].imag()>ret){idx++;}
                    for(ll n=idx;n<R.size() && R[n].imag()-pt[k].imag()<ret;n++){ret=min(ret,abs(R[n]-pt[k]));}
                }
                inplace_merge(pt.begin()+j,pt.begin()+m,j+i*2<pt.size()?pt.begin()+j+2*i:pt.end(),[](const P &a,const P &b){return a.imag()==b.imag()?a.real()<b.real():a.imag()<b.imag();});
            }
        }
        return ret;
    }
    
    P centerofgravity(const vector<P> &pt){
        P ret(0,0);
        D wt=0;
        for(int i=2;i<pt.size();i++){
            D w2=cross(pt[i-1]-pt[0],pt[i]-pt[0]);
            P p=(pt[0]+pt[i-1]+pt[i])/(D)3;
            wt+=w2;
            ret+=p*w2;
        }
        return ret/wt;
    }
    
    void segment_arrangement(const vector<pair<P,P>> &L,vector<pair<int,int>> &seg,vector<P> &pt){
        int N=L.size();
        for(int i=0;i<N;i++){
            pt.push_back(L[i].F);
            pt.push_back(L[i].S);
            for(int j=i+1;j<N;j++){
                if(intersectSS(L[i].F,L[i].S,L[j].F,L[j].S)){
                    pt.push_back(crosspointSS(L[i].F,L[i].S,L[j].F,L[j].S));
                }
            }
        }
        auto less=[](P a,P b){return abs(a-b)<EPS?false:comp(a,b);};
        sort(pt.begin(),pt.end(),less);
        pt.erase(unique(pt.begin(),pt.end(),[](P a,P b){return abs(a-b)<EPS;}),pt.end());
        for(auto &I:L){
            vector<pair<D,int>> on;
            for(int j=0;j<(int)pt.size();j++){
                if(distSP(I.F,I.S,pt[j])<EPS){
                    on.emplace_back(abs(pt[j]-I.F),j);
                }
            }
            sort(on.begin(),on.end());
            for(int j=1;j<(int)on.size();j++){
                seg.emplace_back(on[j-1].S,on[j].S);
            }
        }
        sort(seg.begin(),seg.end());
        seg.erase(unique(seg.begin(),seg.end()),seg.end());
    }
    
    vector<P> convex_of_segments(const vector<pair<P,P>> &L){
        vector<pair<int,int>> seg;
        vector<P> pt;
        segment_arrangement(L,seg,pt);
        vector<vector<int>> edge(pt.size());
        for(auto &I:seg){
            edge[I.F].push_back(I.S);
            edge[I.S].push_back(I.F);
        }
        vector<P> ret;
        function<void(int,int)> dfs=[&](int v,int pre){
            if(pre!=-1 && v==0){return;}
            ret.push_back(pt[v]);
            vector<pair<D,int>> nx;
            for(auto &u:edge[v]){
                D a=arg((pt[u]-pt[v])/(pre==-1 || abs(pt[v]-pt[pre])<EPS?P(1):pt[v]-pt[pre]));
                if(abs(a+PI)<EPS){a=PI;}
                nx.emplace_back(a,u);
            }
            sort(nx.begin(),nx.end());
            dfs(nx[0].S,v);
        };
        dfs(0,-1);
        return ret;
    }
    
    istream & operator >> (istream &i,P &p){D x,y; i>>x>>y; p={x,y}; return i;}
    istream & operator >> (istream &i,C &p){D x,y; i>>x>>y>>p.S; p.F={x,y}; return i;}
};

using namespace Geometry;


int main(){
    ll n;
    cin>>n;
    vector<P> A(n);
    cin>>A;
    vector<pair<P,P>> B(n-1);
    for(int j=1;j<n;j++){B[j-1]={A[j-1],A[j]};}
    cout<<fixed<<setprecision(12)<<area(convex_of_segments(B))<<endl;
    
    
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3520
final_rank: 6

code_snippet: #include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld=long double;
ld eps=1e-9;
/* 幾何の基本 */

#include <complex>

typedef complex<ld> Point;


const ld pi = acos(-1.0);
const ld dtop = pi / 180.;
const ld ptod = 1. / dtop;

namespace std {
	bool operator<(const Point &lhs, const Point &rhs) {
		if (lhs.real() < rhs.real() - eps) return true;
		if (lhs.real() > rhs.real() + eps) return false;
		return lhs.imag() < rhs.imag();
	}
}

// 点の入力
Point input_Point() {
	ld x, y;
	cin >> x >> y;
	return Point(x, y);
}

// 誤差つき等号判定
bool eq(const ld a, const ld b) {
	return (abs(a - b) < eps);
}

// 内積
ld dot(const Point& a, const Point& b) {
	return real(conj(a) * b);
}

// 外積
ld cross(const Point& a, const Point& b) {
	return imag(conj(a) * b);
}

// 直線の定義
class Line {
public:
	Point a, b;
	Line() : a(Point(0, 0)), b(Point(0, 0)) {}
	Line(Point a, Point b) : a(a), b(b) {}
	Point operator[](const int _num)const {
		if (_num == 0)return a;
		else if (_num == 1)return b;
		else {
			assert(false);
			return Point();
		}
	}
};

// 円の定義
class Circle {
public:
	Point p;
	ld r;
	Circle() : p(Point(0, 0)), r(0) {}
	Circle(Point p, ld r) : p(p), r(r) {}
};

// ccw
// 1: a,b,cが反時計周りの順に並ぶ
//-1: a,b,cが時計周りの順に並ぶ
// 2: c,a,bの順に直線に並ぶ
//-2: a,b,cの順に直線に並ぶ
// 0: a,c,bの順に直線に並ぶ
int ccw(const Point& a, const Point &b, const Point &c) {
	const Point nb(b - a);
	const Point nc(c - a);
	if (cross(nb, nc) > eps) return 1;   // a,b,cが反時計周りの順に並ぶ
	if (cross(nb, nc) < -eps) return -1; // a,b,cが時計周りの順に並ぶ
	if (dot(nb, nc) < 0) return 2;       // c,a,bの順に直線に並ぶ
	if (norm(nb) < norm(nc)) return -2;  // a,b,cの順に直線に並ぶ
	return 0;                          // a,c,bの順に直線に並ぶ
}


/* 交差判定 */

// 直線と直線の交差判定
bool isis_ll(const Line& l, const Line& m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}

// 直線と線分の交差判定
bool isis_ls(const Line& l, const Line& s) {
	return isis_ll(l, s) &&
		(cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}

// 線分と線分の交差判定
bool isis_ss(const Line& s, const Line& t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
		ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// 点の直線上判定
bool isis_lp(const Line& l, const Point& p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}

// 点の線分上判定
bool isis_sp(const Line& s, const Point& p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// 垂線の足
Point proj(const Line &l, const Point& p) {
	ld t = dot(p - l.a, l.b - l.a) / norm(l.a - l.b);
	return l.a + t * (l.b - l.a);
}

//線対象の位置にある点
Point reflect(const Line &l, const Point &p) {
	Point pr = proj(l, p);
	return pr * 2.l - p;
}

// 直線と直線の交点
Point is_ll(const Line &s, const Line& t) {
	Point sv = s.b - s.a, tv = t.b - t.a;
	assert(cross(sv, tv) != 0);
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
// 直線と直線の交点
vector<Point> is_ll2(const Line &s, const Line& t) {
	Point sv = s.b - s.a, tv = t.b - t.a;
	if (cross(sv, tv) != 0)return vector<Point>(1, is_ll(s, t));
	else {
		vector<Point>ans;
		for (int k = 0; k < 2; ++k) {
			if (isis_sp(s, t[k]) && find(ans.begin(), ans.end(), t[k]) == ans.end())ans.push_back(t[k]);
			if (isis_sp(t, s[k]) && find(ans.begin(), ans.end(), s[k]) == ans.end())ans.push_back(s[k]);
		}
		return ans;
	}
}
// 線分と線分の交点
//　重なってる部分あるとassert(false)
Point is_ss(const Line &s, const Line& t) {
	if (isis_ss(s, t)) {
		for (int k = 0; k < 2; ++k) {
			for (int l = 0; l < 2; ++l) {
				if (s[k] == t[l])return s[k];
			}
		}
		return is_ll(s, t);
	}
	else {
		//先にisis_ssしてね
		assert(false);
		return Point(0, 0);
	}
}
// 線分と線分の交点
vector<Point> is_ss2(const Line &s, const Line& t) {
	vector<Point> kouho(is_ll2(s, t));
	vector<Point>ans;
	for (auto p : kouho) {
		if (isis_sp(s, p) && isis_sp(t, p))ans.emplace_back(p);
	}
	return ans;
}
// 直線と点の距離
ld dist_lp(const Line& l, const Point& p) {
	return abs(p - proj(l, p));
}

//直線と直線の距離
ld dist_ll(const Line& l, const Line& m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}

// 直線と線分の距離
ld dist_ls(const Line& l, const Line& s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}

// 線分と点の距離
ld dist_sp(const Line& s, const Point& p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(r - p) : min(abs(s.a - p), abs(s.b - p));
}

// 線分と線分の距離
ld dist_ss(const Line& s, const Line& t) {
	if (isis_ss(s, t)) return 0;
	return min({ dist_sp(s, t.a), dist_sp(s, t.b), dist_sp(t, s.a), dist_sp(t, s.b) });
}


//直線と直線の二等分線のベクトル
Line line_bisection(const Line &s, const Line &t) {
	const Point laglanju(is_ll(s, t));
	const Point avec = !(abs(laglanju - s[0])<eps) ? s[0] - laglanju : s[1] - laglanju;
	const Point bvec = !(abs(laglanju - t[0])<eps) ? t[0] - laglanju : t[1] - laglanju;

	return Line(laglanju, laglanju + (abs(bvec)*avec + abs(avec)*bvec) / (abs(avec) + abs(bvec)));
}
//点と点の垂直二等分線　aを左に見ながら
Line point_bisection(const Point&a, const Point&b) {
	const Point cen((a + b) / 2.l);
	const Point vec = (b - a)*Point(0, 1);
	return Line(cen, cen + vec);
}

//三つの点からなる外心
Point outer_center(const vector<Point>&ps) {
	assert(ps.size() == 3);
	Line l1 = point_bisection(ps[0], ps[1]);
	Line l2 = point_bisection(ps[1], ps[2]);
	return is_ll(l1, l2);
}


//三つの直線からなる内心
//三つの直線が並行でないことは確かめといてね
Point  inner_center(const vector<Line>&ls) {
	vector<Point>vertics;
	for (int i = 0; i <static_cast<int>(ls.size()); ++i) {
		vertics.push_back(is_ll(ls[i], ls[(i + 1) % 3]));
	}
	if (vertics[0] == vertics[1] || vertics[1] == vertics[2] || vertics[2] == vertics[0])return vertics[0];
	Line bi1(line_bisection(Line(vertics[0], vertics[1]), Line(vertics[0], vertics[2])));
	Line bi2(line_bisection(Line(vertics[1], vertics[2]), Line(vertics[1], vertics[0])));
	if (bi1[0] == bi2[0])return bi1[0];
	else {
		return is_ll(bi1, bi2);
	}
}

//三つの直線からなる傍心
//三つの直線が並行でないことは確かめといてね
vector<Point>  ex_center(const vector<Line>&ls) {
	vector<Point>vertics;
	for (int i = 0; i < static_cast<int>(ls.size()); ++i) {
		vertics.push_back(is_ll(ls[i], ls[(i + 1) % 3]));
	}
	if (abs(vertics[0] - vertics[1])<eps || abs(vertics[1] - vertics[2])<eps || (abs(vertics[2] - vertics[0])<eps))return vector<Point>();
	vector<Point>ecs;
	for (int i = 0; i < 3; ++i) {
		Line bi1(line_bisection(Line(vertics[i], vertics[i] * 2.0l - vertics[(i + 2) % 3]), Line(vertics[i], vertics[(i + 1) % 3])));
		Line bi2(line_bisection(Line(vertics[(i + 1) % 3], vertics[(i + 1) % 3] * 2.0l - vertics[(i + 2) % 3]), Line(vertics[(i + 1) % 3], vertics[i])));
		ecs.push_back(is_ll(bi1, bi2));
	}
	return ecs;
}


//a,b:並行
//c:並行でない
//三つの直線から同距離の位置を求める。
vector<Point>  same_dis(const vector<Line>&ls) {
	vector<Point>vertics;
	vertics.push_back(is_ll(ls[0], ls[2]));
	vertics.push_back(is_ll(ls[1], ls[2]));

	if (abs(vertics[0] - vertics[1]) < eps)return vector<Point>{vertics[0]};
	Line bis(line_bisection(ls[0], ls[1]));
	vector<Point>ecs;

	Line abi(line_bisection(Line(vertics[0], vertics[1]), ls[0]));
	ecs.push_back(is_ll(bis, abi));


	Line bbi(line_bisection(Line(vertics[0], 2.l*vertics[0] - vertics[1]), ls[0]));
	ecs.push_back(is_ll(bis, bbi));

	return ecs;
}
/* 円 */

// 円と円の交点
vector<Point> is_cc(const Circle& c1, const Circle& c2) {
	vector<Point> res;
	ld d = abs(c1.p - c2.p);
	ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
	ld dfr = c1.r * c1.r - rc * rc;
	if (abs(dfr) < eps) dfr = 0.0;
	else if (dfr < 0.0) return res; // no intersection
	ld rs = sqrt(dfr);
	Point diff = (c2.p - c1.p) / d;
	res.push_back(c1.p + diff * Point(rc, rs));
	if (dfr != 0.0) res.push_back(c1.p + diff * Point(rc, -rs));
	return res;
}

/*
点が円の中にいるか
0 => out
1 => on
2 => in*/
int is_in_Circle(const  Point& p, const Circle &cir) {
	ld dis = abs(cir.p - p);
	if (dis > cir.r + eps)return 0;
	else if (dis < cir.r - eps)return 2;
	else return 1;
}
int is_in_Circle(const Circle &cir, const  Point& p) {
	ld dis = abs(cir.p - p);
	if (dis > cir.r + eps)return 0;
	else if (dis < cir.r - eps)return 2;
	else return 1;
}
/*
円lcが円rcの中にいるか
0 => out
1 => on
2 => in*/
int Circle_in_Circle(const Circle &lc, const  Circle&rc) {
	ld dis = abs(lc.p - rc.p);
	if (dis < rc.r - lc.r - eps)return 2;
	else if (dis>rc.r - lc.r + eps)return 0;
	else return 1;
}

// 円と直線の交点
vector<Point> is_lc(const Circle& c, const Line& l) {
	vector<Point> res;
	ld d = dist_lp(l, c.p);
	if (d < c.r + eps) {
		ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
		Point nor = (l.a - l.b) / abs(l.a - l.b);
		res.push_back(proj(l, c.p) + len * nor);
		res.push_back(proj(l, c.p) - len * nor);
	}
	return res;
}

// 円と線分の距離
vector<Point> is_sc(const Circle& c, const Line& l) {
	vector<Point> v = is_lc(c, l), res;
	for (Point p : v)
		if (isis_sp(l, p)) res.push_back(p);
	return res;
}

// 円と点の接線
vector<Line> tangent_cp(const Circle& c, const Point& p) {
	vector<Line> ret;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r * c.r);
	if (isnan(l)) { return ret; }
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	ret.push_back(Line(p, p + v1));
	if (l < eps) return ret;
	ret.push_back(Line(p, p + v2));
	return ret;
}

// 円と円の接線
vector<Line> tangent_cc(const Circle& c1, const Circle& c2) {
	vector<Line> ret;
	if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
		Point center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
		ret = tangent_cp(c1, center);
	}
	if (abs(c1.r - c2.r) > eps) {
		Point out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
		vector<Line> nret = tangent_cp(c1, out);
		ret.insert(ret.end(), nret.begin(), nret.end());
	}
	else {
		Point v = c2.p - c1.p;
		v /= abs(v);
		Point q1 = c1.p + v * Point(0, 1) * c1.r;
		Point q2 = c1.p + v * Point(0, -1) * c1.r;
		ret.push_back(Line(q1, q1 + v));
		ret.push_back(Line(q2, q2 + v));
	}
	return ret;
}
//二つの円の重なり面積
ld two_Circle_area(const Circle&l, const Circle&r) {
	ld dis = abs(l.p - r.p);
	if (dis > l.r + r.r)return 0;
	else if (dis + r.r < l.r) {
		return r.r*r.r*pi;
	}
	else if (dis + l.r < r.r) {
		return l.r*l.r*pi;
	}
	else {
		ld ans = (l.r)*(l.r)*acos((dis*dis + l.r*l.r - r.r*r.r) / (2 * dis*l.r)) +
			(r.r)*(r.r)*acos((dis*dis + r.r*r.r - l.r*l.r) / (2 * dis*r.r)) -
			sqrt(4 * dis*dis*l.r*l.r - (dis*dis + l.r*l.r - r.r*r.r)*(dis*dis + l.r*l.r - r.r*r.r)) / 2;
		return ans;
	}

}

/* 多角形 */

typedef vector<Point> Polygon;



//多角形(複数の点)の最小包含円をO(N=頂点数)で求めるアルゴリズム
//同一直線上に三つの点がないこと
#include<random>
Circle welzl(vector<Point>ps) {
	struct solver {
		Circle solve(vector<Point>&ps, vector<Point>&rs) {
			if (ps.empty() || rs.size() == 3) {
				if (rs.size() == 1) {
					return Circle(Point(rs[0]), 0);
				}
				else if (rs.size() == 2) {
					return Circle((rs[0] + rs[1]) / 2.0l, abs(rs[1] - rs[0]) / 2);
				}
				else if (rs.size() == 3) {
					vector<Line> ls(3);
					for (int i = 0; i < 3; ++i) {
						ls[i] = Line(rs[i], rs[(i + 1) % 3]);
					}
					Point center = outer_center(rs);
					return Circle(center, abs(center - rs[0]));
				}
				else {
					return Circle(Point(), 0);
				}
			}
			else {

				Point p_ba = ps.back();
				ps.pop_back();
				Circle d = solve(ps, rs);
				ps.push_back(p_ba);
				if (is_in_Circle(d, p_ba)) {
					return d;
				}
				else {
					rs.push_back(p_ba);
					ps.pop_back();
					auto ans = solve(ps, rs);
					ps.push_back(p_ba);
					rs.pop_back();
					return ans;
				}
			}
		}
	}so;
	std::random_device rd;
	std::mt19937 mt(rd());
	shuffle(ps.begin(), ps.end(), mt);
	vector<Point>rs;
	Circle ans = so.solve(ps, rs);
	return ans;
}
// 面積
ld get_area(const Polygon &p) {
	ld res = 0;
	int n = p.size();
	for (int j = 0; j<n; ++j) res += cross(p[j], p[(j + 1) % n]);
	return res / 2;
}

//多角形の回転方向
bool is_counter_clockwise(const Polygon &poly) {
	ld angle = 0;
	int n = poly.size();
	for(int i=0;i<n;++i) {
		Point a = poly[i], b = poly[(i + 1) % n], c = poly[(i + 2) % n];
		angle += arg((c - b) / (b - a));
	}
	return angle > eps;
}

// 円の内外判定
/*0 => out
1 => on
2 => in*/
int is_in_Polygon(const Polygon &poly, const  Point& p) {
	ld angle = 0;
	int n = poly.size();
	for(int i=0;i<n;++i) {
		Point a = poly[i], b = poly[(i + 1) % n];
		if (isis_sp(Line(a, b), p)) return 1;
		angle += arg((b - p) / (a - p));
	}
	return eq(angle, 0) ? 0 : 2;
}
//円の内外判定2　高速
enum { out, on, in };
int convex_contains(const Polygon &P, const Point &p) {
	const int n = P.size();
	Point g = (P[0] + P[n / 3] + P[2 * n / 3]) / 3.0l; // inner-point
	int a = 0, b = n;
	while (a + 1 < b) { // invariant: c is in fan g-P[a]-P[b]
		int c = (a + b) / 2;
		if (cross(P[a] - g, P[c] - g) > 0) { // angle < 180 deg
			if (cross(P[a] - g, p - g) > 0 && cross(P[c] - g, p - g) < 0) b = c;
			else                                                  a = c;
		}
		else {
			if (cross(P[a] - g, p - g) < 0 && cross(P[c] - g, p - g) > 0) a = c;
			else                                                  b = c;
		}
	}
	b %= n;
	if (cross(P[a] - p, P[b] - p) < 0) return 0;
	if (cross(P[a] - p, P[b] - p) > 0) return 2;
	return 1;
}

// 凸包
//点や線を返すことも有り得るので注意
Polygon convex_hull(vector<Point> ps) {
	int n = ps.size();
	int k = 0;
	sort(ps.begin(), ps.end());
	Polygon ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++])
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--])
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}



//凸カット
vector<Polygon> convex_cut(const Polygon &ps, const Line& l) {
	int n = ps.size();
	Polygon q;
	Polygon r;
	for(int i=0;i<n;++i) {
		Point a = ps[i], b = ps[(i + 1) % n];
		Line m = Line(a, b);
		if (ccw(l.a, l.b, a) != -1) q.push_back(a);
		if (ccw(l.a, l.b, a) != 1) r.push_back(a);
		if (ccw(l.a, l.b, a) * ccw(l.a, l.b, b) < 0 && isis_ll(l, m)) {
			q.push_back(is_ll(l, m));
			r.push_back(is_ll(l, m));
		}
	}
	const vector<Polygon>polys{ q,r };
	return polys;
}


/* アレンジメント */
void add_Point(vector<Point> &ps, const Point p) {
	for (Point q : ps) if (abs(q - p) < eps) return;
	ps.push_back(p);
}


struct Edge {
	int src;
	int dest;
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

void add_edge(Graph &g, int src, int dest) {
	g[src].push_back(Edge{ src, dest});
	g[dest].push_back(Edge{ dest, src});
}

Graph segment_arrangement(const vector<Line> &s, const vector<Point> &p) {
	int n = p.size(), m = s.size();
	Graph g(n);
	for(int i=0;i<m;++i){
		vector<pair<ld, int>> vec;
		for(int j=0;j<n;++j){
			if (isis_sp(s[i], p[j]))
				vec.emplace_back(abs(s[i].a - p[j]), j);
		}
		sort(vec.begin(),vec.end());
		for(int j=0;j<vec.size()-1;++j) {
			int from = vec[j].second, to = vec[j + 1].second;
			
			if (find_if(g[from].begin(), g[from].end(), [&](const Edge&e) {
				return e.dest == to; })==g[from].end())add_edge(g, from, to);
			
		}
	}
	return g;
}
pair<vector<Point>, Graph> sennbunn_arrangement(const vector<Line>&s) {
	vector<Point>crss;
	for (int i = 0; i < static_cast<int>(s.size()); ++i) {
		for (int j = i + 1; j < static_cast<int>(s.size()); ++j) {
			if (isis_ss(s[i], s[j])) {
				crss.push_back(is_ll2(s[i], s[j])[0]);
			}
		}
	}
	for (int i = 0; i <static_cast<int>(s.size()); ++i) {
		crss.push_back(s[i][0]);
		crss.push_back(s[i][1]);
	}
	sort(crss.begin(), crss.end());
	crss.erase(unique(crss.begin(), crss.end(),[](const Point &lhs, const Point &rhs) {
		return abs(lhs-rhs)<eps;
	}), crss.end());

	return make_pair(crss, segment_arrangement(s, crss));
}

pair<int,int> dfs(vector<int>&depths,int de,vector<int>&used,const int now,const int from,vector<int>&prevs,ld &ans, const vector<Point>&ps,const Graph&g) {
	vector<pair<ld,int>>next_points;
	depths[now]=de;
	//cout<<now<<endl;
	Point from_p=from==-1?ps[now]+Point(-3e6,0):ps[from];
	Point now_p=ps[now];
	for (auto e : g[now]) {
		if(e.dest==from)continue;
		Point next_p=ps[e.dest];

		ld costheta=dot(from_p-now_p,next_p-now_p)/(abs(from_p-now_p)*abs(next_p-now_p));
		costheta*=0.3;
		ld d=acos(costheta);
		if (ccw(from_p, now_p, next_p) != 1) {
			d=2*pi-d;
		}
		next_points.push_back(make_pair(d,e.dest));
	}
	sort(next_points.begin(),next_points.end());

	int flag=-1;
	for (auto n_p : next_points) {
		if (flag != -1) {
			if (n_p.second == flag) {
				flag=-1;
				continue;
			}
			else {
				continue;
			}
		}
		if (prevs[n_p.second] != -1) {
			Polygon lpoly;
			int rid=now;
			int lid=n_p.second;

			Polygon rpoly;
			while (depths[rid] > depths[lid]) {
				rpoly.push_back(ps[rid]);
				rid=prevs[rid];
			}
			while (depths[rid] < depths[lid]) {
				lpoly.push_back(ps[lid]);
				lid = prevs[lid];
			}
			while (rid != lid) {
				rpoly.push_back(ps[rid]);
				lpoly.push_back(ps[lid]);
				rid=prevs[rid];
				lid=prevs[lid];
			}
			Polygon poly(lpoly);
			poly.push_back(ps[rid]);
			for (int i = 0; i < rpoly.size(); ++i) {
				poly.push_back(rpoly[rpoly.size()-i-1]);
			}
			
			ld plus=get_area(poly);
			ans+=abs(-plus);
			used[now] = true;
			return make_pair(n_p.second,now);
		}
		prevs[n_p.second]=now;
		auto  num=dfs(depths,de+1,used,n_p.second,now,prevs,ans,ps,g);
		prevs[n_p.second]=-1;
		if (num.first != -1) {
			if (num.first == now) {
				flag=num.second;
			}
			else {

				used[now] = true;
				return num;
			}
		}
	}
	//assert(flag==-1);
	used[now]=true;
	return make_pair(-1,-1);
}

int main()
{
	int N;cin>>N;
	vector<Point>ps;
	for (int i = 0; i < N; ++i) {
		int a,b;cin>>a>>b;
		ps.push_back(Point(a,b));
	}
	vector<Line>ls;
	for (int i = 0; i < N - 1; ++i) {
		Line l(ps[i],ps[i+1]);
		ls.emplace_back(l);
	}

	auto p=sennbunn_arrangement(ls);
	ld ans=0;
	vector<int>prevs(p.first.size(),-1);
	prevs[0]=-2;
	vector<int>used(p.first.size(),false);
	vector<int>depths(p.first.size(),-1);
	dfs(depths,0,used,0,-1,prevs,ans,p.first,p.second);
	cout<<setprecision(10)<<fixed<<ans<<endl;
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3500
final_rank: 4

code_snippet: #include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld=long double;
ld eps=1e-9;
/* 幾何の基本 */

#include <complex>

typedef complex<ld> Point;


const ld pi = acos(-1.0);
const ld dtop = pi / 180.;
const ld ptod = 1. / dtop;

namespace std {
	bool operator<(const Point &lhs, const Point &rhs) {
		if (lhs.real() < rhs.real() - eps) return true;
		if (lhs.real() > rhs.real() + eps) return false;
		return lhs.imag() < rhs.imag();
	}
}

// 点の入力
Point input_Point() {
	ld x, y;
	cin >> x >> y;
	return Point(x, y);
}

// 誤差つき等号判定
bool eq(const ld a, const ld b) {
	return (abs(a - b) < eps);
}

// 内積
ld dot(const Point& a, const Point& b) {
	return real(conj(a) * b);
}

// 外積
ld cross(const Point& a, const Point& b) {
	return imag(conj(a) * b);
}

// 直線の定義
class Line {
public:
	Point a, b;
	Line() : a(Point(0, 0)), b(Point(0, 0)) {}
	Line(Point a, Point b) : a(a), b(b) {}
	Point operator[](const int _num)const {
		if (_num == 0)return a;
		else if (_num == 1)return b;
		else {
			assert(false);
			return Point();
		}
	}
};

// 円の定義
class Circle {
public:
	Point p;
	ld r;
	Circle() : p(Point(0, 0)), r(0) {}
	Circle(Point p, ld r) : p(p), r(r) {}
};

// ccw
// 1: a,b,cが反時計周りの順に並ぶ
//-1: a,b,cが時計周りの順に並ぶ
// 2: c,a,bの順に直線に並ぶ
//-2: a,b,cの順に直線に並ぶ
// 0: a,c,bの順に直線に並ぶ
int ccw(const Point& a, const Point &b, const Point &c) {
	const Point nb(b - a);
	const Point nc(c - a);
	if (cross(nb, nc) > eps) return 1;   // a,b,cが反時計周りの順に並ぶ
	if (cross(nb, nc) < -eps) return -1; // a,b,cが時計周りの順に並ぶ
	if (dot(nb, nc) < 0) return 2;       // c,a,bの順に直線に並ぶ
	if (norm(nb) < norm(nc)) return -2;  // a,b,cの順に直線に並ぶ
	return 0;                          // a,c,bの順に直線に並ぶ
}


/* 交差判定 */

// 直線と直線の交差判定
bool isis_ll(const Line& l, const Line& m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}

// 直線と線分の交差判定
bool isis_ls(const Line& l, const Line& s) {
	return isis_ll(l, s) &&
		(cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}

// 線分と線分の交差判定
bool isis_ss(const Line& s, const Line& t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
		ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// 点の直線上判定
bool isis_lp(const Line& l, const Point& p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}

// 点の線分上判定
bool isis_sp(const Line& s, const Point& p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// 垂線の足
Point proj(const Line &l, const Point& p) {
	ld t = dot(p - l.a, l.b - l.a) / norm(l.a - l.b);
	return l.a + t * (l.b - l.a);
}

//線対象の位置にある点
Point reflect(const Line &l, const Point &p) {
	Point pr = proj(l, p);
	return pr * 2.l - p;
}

// 直線と直線の交点
Point is_ll(const Line &s, const Line& t) {
	Point sv = s.b - s.a, tv = t.b - t.a;
	assert(cross(sv, tv) != 0);
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
// 直線と直線の交点
vector<Point> is_ll2(const Line &s, const Line& t) {
	Point sv = s.b - s.a, tv = t.b - t.a;
	if (cross(sv, tv) != 0)return vector<Point>(1, is_ll(s, t));
	else {
		vector<Point>ans;
		for (int k = 0; k < 2; ++k) {
			if (isis_sp(s, t[k]) && find(ans.begin(), ans.end(), t[k]) == ans.end())ans.push_back(t[k]);
			if (isis_sp(t, s[k]) && find(ans.begin(), ans.end(), s[k]) == ans.end())ans.push_back(s[k]);
		}
		return ans;
	}
}
// 線分と線分の交点
//　重なってる部分あるとassert(false)
Point is_ss(const Line &s, const Line& t) {
	if (isis_ss(s, t)) {
		for (int k = 0; k < 2; ++k) {
			for (int l = 0; l < 2; ++l) {
				if (s[k] == t[l])return s[k];
			}
		}
		return is_ll(s, t);
	}
	else {
		//先にisis_ssしてね
		assert(false);
		return Point(0, 0);
	}
}
// 線分と線分の交点
vector<Point> is_ss2(const Line &s, const Line& t) {
	vector<Point> kouho(is_ll2(s, t));
	vector<Point>ans;
	for (auto p : kouho) {
		if (isis_sp(s, p) && isis_sp(t, p))ans.emplace_back(p);
	}
	return ans;
}
// 直線と点の距離
ld dist_lp(const Line& l, const Point& p) {
	return abs(p - proj(l, p));
}

//直線と直線の距離
ld dist_ll(const Line& l, const Line& m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}

// 直線と線分の距離
ld dist_ls(const Line& l, const Line& s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}

// 線分と点の距離
ld dist_sp(const Line& s, const Point& p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(r - p) : min(abs(s.a - p), abs(s.b - p));
}

// 線分と線分の距離
ld dist_ss(const Line& s, const Line& t) {
	if (isis_ss(s, t)) return 0;
	return min({ dist_sp(s, t.a), dist_sp(s, t.b), dist_sp(t, s.a), dist_sp(t, s.b) });
}


//直線と直線の二等分線のベクトル
Line line_bisection(const Line &s, const Line &t) {
	const Point laglanju(is_ll(s, t));
	const Point avec = !(abs(laglanju - s[0])<eps) ? s[0] - laglanju : s[1] - laglanju;
	const Point bvec = !(abs(laglanju - t[0])<eps) ? t[0] - laglanju : t[1] - laglanju;

	return Line(laglanju, laglanju + (abs(bvec)*avec + abs(avec)*bvec) / (abs(avec) + abs(bvec)));
}
//点と点の垂直二等分線　aを左に見ながら
Line point_bisection(const Point&a, const Point&b) {
	const Point cen((a + b) / 2.l);
	const Point vec = (b - a)*Point(0, 1);
	return Line(cen, cen + vec);
}

//三つの点からなる外心
Point outer_center(const vector<Point>&ps) {
	assert(ps.size() == 3);
	Line l1 = point_bisection(ps[0], ps[1]);
	Line l2 = point_bisection(ps[1], ps[2]);
	return is_ll(l1, l2);
}


//三つの直線からなる内心
//三つの直線が並行でないことは確かめといてね
Point  inner_center(const vector<Line>&ls) {
	vector<Point>vertics;
	for (int i = 0; i <static_cast<int>(ls.size()); ++i) {
		vertics.push_back(is_ll(ls[i], ls[(i + 1) % 3]));
	}
	if (vertics[0] == vertics[1] || vertics[1] == vertics[2] || vertics[2] == vertics[0])return vertics[0];
	Line bi1(line_bisection(Line(vertics[0], vertics[1]), Line(vertics[0], vertics[2])));
	Line bi2(line_bisection(Line(vertics[1], vertics[2]), Line(vertics[1], vertics[0])));
	if (bi1[0] == bi2[0])return bi1[0];
	else {
		return is_ll(bi1, bi2);
	}
}

//三つの直線からなる傍心
//三つの直線が並行でないことは確かめといてね
vector<Point>  ex_center(const vector<Line>&ls) {
	vector<Point>vertics;
	for (int i = 0; i < static_cast<int>(ls.size()); ++i) {
		vertics.push_back(is_ll(ls[i], ls[(i + 1) % 3]));
	}
	if (abs(vertics[0] - vertics[1])<eps || abs(vertics[1] - vertics[2])<eps || (abs(vertics[2] - vertics[0])<eps))return vector<Point>();
	vector<Point>ecs;
	for (int i = 0; i < 3; ++i) {
		Line bi1(line_bisection(Line(vertics[i], vertics[i] * 2.0l - vertics[(i + 2) % 3]), Line(vertics[i], vertics[(i + 1) % 3])));
		Line bi2(line_bisection(Line(vertics[(i + 1) % 3], vertics[(i + 1) % 3] * 2.0l - vertics[(i + 2) % 3]), Line(vertics[(i + 1) % 3], vertics[i])));
		ecs.push_back(is_ll(bi1, bi2));
	}
	return ecs;
}


//a,b:並行
//c:並行でない
//三つの直線から同距離の位置を求める。
vector<Point>  same_dis(const vector<Line>&ls) {
	vector<Point>vertics;
	vertics.push_back(is_ll(ls[0], ls[2]));
	vertics.push_back(is_ll(ls[1], ls[2]));

	if (abs(vertics[0] - vertics[1]) < eps)return vector<Point>{vertics[0]};
	Line bis(line_bisection(ls[0], ls[1]));
	vector<Point>ecs;

	Line abi(line_bisection(Line(vertics[0], vertics[1]), ls[0]));
	ecs.push_back(is_ll(bis, abi));


	Line bbi(line_bisection(Line(vertics[0], 2.l*vertics[0] - vertics[1]), ls[0]));
	ecs.push_back(is_ll(bis, bbi));

	return ecs;
}
/* 円 */

// 円と円の交点
vector<Point> is_cc(const Circle& c1, const Circle& c2) {
	vector<Point> res;
	ld d = abs(c1.p - c2.p);
	ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
	ld dfr = c1.r * c1.r - rc * rc;
	if (abs(dfr) < eps) dfr = 0.0;
	else if (dfr < 0.0) return res; // no intersection
	ld rs = sqrt(dfr);
	Point diff = (c2.p - c1.p) / d;
	res.push_back(c1.p + diff * Point(rc, rs));
	if (dfr != 0.0) res.push_back(c1.p + diff * Point(rc, -rs));
	return res;
}

/*
点が円の中にいるか
0 => out
1 => on
2 => in*/
int is_in_Circle(const  Point& p, const Circle &cir) {
	ld dis = abs(cir.p - p);
	if (dis > cir.r + eps)return 0;
	else if (dis < cir.r - eps)return 2;
	else return 1;
}
int is_in_Circle(const Circle &cir, const  Point& p) {
	ld dis = abs(cir.p - p);
	if (dis > cir.r + eps)return 0;
	else if (dis < cir.r - eps)return 2;
	else return 1;
}
/*
円lcが円rcの中にいるか
0 => out
1 => on
2 => in*/
int Circle_in_Circle(const Circle &lc, const  Circle&rc) {
	ld dis = abs(lc.p - rc.p);
	if (dis < rc.r - lc.r - eps)return 2;
	else if (dis>rc.r - lc.r + eps)return 0;
	else return 1;
}

// 円と直線の交点
vector<Point> is_lc(const Circle& c, const Line& l) {
	vector<Point> res;
	ld d = dist_lp(l, c.p);
	if (d < c.r + eps) {
		ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
		Point nor = (l.a - l.b) / abs(l.a - l.b);
		res.push_back(proj(l, c.p) + len * nor);
		res.push_back(proj(l, c.p) - len * nor);
	}
	return res;
}

// 円と線分の距離
vector<Point> is_sc(const Circle& c, const Line& l) {
	vector<Point> v = is_lc(c, l), res;
	for (Point p : v)
		if (isis_sp(l, p)) res.push_back(p);
	return res;
}

// 円と点の接線
vector<Line> tangent_cp(const Circle& c, const Point& p) {
	vector<Line> ret;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r * c.r);
	if (isnan(l)) { return ret; }
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	ret.push_back(Line(p, p + v1));
	if (l < eps) return ret;
	ret.push_back(Line(p, p + v2));
	return ret;
}

// 円と円の接線
vector<Line> tangent_cc(const Circle& c1, const Circle& c2) {
	vector<Line> ret;
	if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
		Point center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
		ret = tangent_cp(c1, center);
	}
	if (abs(c1.r - c2.r) > eps) {
		Point out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
		vector<Line> nret = tangent_cp(c1, out);
		ret.insert(ret.end(), nret.begin(), nret.end());
	}
	else {
		Point v = c2.p - c1.p;
		v /= abs(v);
		Point q1 = c1.p + v * Point(0, 1) * c1.r;
		Point q2 = c1.p + v * Point(0, -1) * c1.r;
		ret.push_back(Line(q1, q1 + v));
		ret.push_back(Line(q2, q2 + v));
	}
	return ret;
}
//二つの円の重なり面積
ld two_Circle_area(const Circle&l, const Circle&r) {
	ld dis = abs(l.p - r.p);
	if (dis > l.r + r.r)return 0;
	else if (dis + r.r < l.r) {
		return r.r*r.r*pi;
	}
	else if (dis + l.r < r.r) {
		return l.r*l.r*pi;
	}
	else {
		ld ans = (l.r)*(l.r)*acos((dis*dis + l.r*l.r - r.r*r.r) / (2 * dis*l.r)) +
			(r.r)*(r.r)*acos((dis*dis + r.r*r.r - l.r*l.r) / (2 * dis*r.r)) -
			sqrt(4 * dis*dis*l.r*l.r - (dis*dis + l.r*l.r - r.r*r.r)*(dis*dis + l.r*l.r - r.r*r.r)) / 2;
		return ans;
	}

}

/* 多角形 */

typedef vector<Point> Polygon;



//多角形(複数の点)の最小包含円をO(N=頂点数)で求めるアルゴリズム
//同一直線上に三つの点がないこと
#include<random>
Circle welzl(vector<Point>ps) {
	struct solver {
		Circle solve(vector<Point>&ps, vector<Point>&rs) {
			if (ps.empty() || rs.size() == 3) {
				if (rs.size() == 1) {
					return Circle(Point(rs[0]), 0);
				}
				else if (rs.size() == 2) {
					return Circle((rs[0] + rs[1]) / 2.0l, abs(rs[1] - rs[0]) / 2);
				}
				else if (rs.size() == 3) {
					vector<Line> ls(3);
					for (int i = 0; i < 3; ++i) {
						ls[i] = Line(rs[i], rs[(i + 1) % 3]);
					}
					Point center = outer_center(rs);
					return Circle(center, abs(center - rs[0]));
				}
				else {
					return Circle(Point(), 0);
				}
			}
			else {

				Point p_ba = ps.back();
				ps.pop_back();
				Circle d = solve(ps, rs);
				ps.push_back(p_ba);
				if (is_in_Circle(d, p_ba)) {
					return d;
				}
				else {
					rs.push_back(p_ba);
					ps.pop_back();
					auto ans = solve(ps, rs);
					ps.push_back(p_ba);
					rs.pop_back();
					return ans;
				}
			}
		}
	}so;
	std::random_device rd;
	std::mt19937 mt(rd());
	shuffle(ps.begin(), ps.end(), mt);
	vector<Point>rs;
	Circle ans = so.solve(ps, rs);
	return ans;
}
// 面積
ld get_area(const Polygon &p) {
	ld res = 0;
	int n = p.size();
	for (int j = 0; j<n; ++j) res += cross(p[j], p[(j + 1) % n]);
	return res / 2;
}

//多角形の回転方向
bool is_counter_clockwise(const Polygon &poly) {
	ld angle = 0;
	int n = poly.size();
	for(int i=0;i<n;++i) {
		Point a = poly[i], b = poly[(i + 1) % n], c = poly[(i + 2) % n];
		angle += arg((c - b) / (b - a));
	}
	return angle > eps;
}

// 円の内外判定
/*0 => out
1 => on
2 => in*/
int is_in_Polygon(const Polygon &poly, const  Point& p) {
	ld angle = 0;
	int n = poly.size();
	for(int i=0;i<n;++i) {
		Point a = poly[i], b = poly[(i + 1) % n];
		if (isis_sp(Line(a, b), p)) return 1;
		angle += arg((b - p) / (a - p));
	}
	return eq(angle, 0) ? 0 : 2;
}
//円の内外判定2　高速
enum { out, on, in };
int convex_contains(const Polygon &P, const Point &p) {
	const int n = P.size();
	Point g = (P[0] + P[n / 3] + P[2 * n / 3]) / 3.0l; // inner-point
	int a = 0, b = n;
	while (a + 1 < b) { // invariant: c is in fan g-P[a]-P[b]
		int c = (a + b) / 2;
		if (cross(P[a] - g, P[c] - g) > 0) { // angle < 180 deg
			if (cross(P[a] - g, p - g) > 0 && cross(P[c] - g, p - g) < 0) b = c;
			else                                                  a = c;
		}
		else {
			if (cross(P[a] - g, p - g) < 0 && cross(P[c] - g, p - g) > 0) a = c;
			else                                                  b = c;
		}
	}
	b %= n;
	if (cross(P[a] - p, P[b] - p) < 0) return 0;
	if (cross(P[a] - p, P[b] - p) > 0) return 2;
	return 1;
}

// 凸包
//点や線を返すことも有り得るので注意
Polygon convex_hull(vector<Point> ps) {
	int n = ps.size();
	int k = 0;
	sort(ps.begin(), ps.end());
	Polygon ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++])
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--])
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}



//凸カット
vector<Polygon> convex_cut(const Polygon &ps, const Line& l) {
	int n = ps.size();
	Polygon q;
	Polygon r;
	for(int i=0;i<n;++i) {
		Point a = ps[i], b = ps[(i + 1) % n];
		Line m = Line(a, b);
		if (ccw(l.a, l.b, a) != -1) q.push_back(a);
		if (ccw(l.a, l.b, a) != 1) r.push_back(a);
		if (ccw(l.a, l.b, a) * ccw(l.a, l.b, b) < 0 && isis_ll(l, m)) {
			q.push_back(is_ll(l, m));
			r.push_back(is_ll(l, m));
		}
	}
	const vector<Polygon>polys{ q,r };
	return polys;
}


/* アレンジメント */
void add_Point(vector<Point> &ps, const Point p) {
	for (Point q : ps) if (abs(q - p) < eps) return;
	ps.push_back(p);
}


struct Edge {
	int src;
	int dest;
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

void add_edge(Graph &g, int src, int dest) {
	g[src].push_back(Edge{ src, dest});
	g[dest].push_back(Edge{ dest, src});
}

Graph segment_arrangement(const vector<Line> &s, const vector<Point> &p) {
	int n = p.size(), m = s.size();
	Graph g(n);
	for(int i=0;i<m;++i){
		vector<pair<ld, int>> vec;
		for(int j=0;j<n;++j){
			if (isis_sp(s[i], p[j]))
				vec.emplace_back(abs(s[i].a - p[j]), j);
		}
		sort(vec.begin(),vec.end());
		for(int j=0;j<vec.size()-1;++j) {
			int from = vec[j].second, to = vec[j + 1].second;
			
			if (find_if(g[from].begin(), g[from].end(), [&](const Edge&e) {
				return e.dest == to; })==g[from].end())add_edge(g, from, to);
			
		}
	}
	return g;
}
pair<vector<Point>, Graph> sennbunn_arrangement(const vector<Line>&s) {
	vector<Point>crss;
	for (int i = 0; i < static_cast<int>(s.size()); ++i) {
		for (int j = i + 1; j < static_cast<int>(s.size()); ++j) {
			if (isis_ss(s[i], s[j])) {
				crss.push_back(is_ll2(s[i], s[j])[0]);
			}
		}
	}
	for (int i = 0; i <static_cast<int>(s.size()); ++i) {
		crss.push_back(s[i][0]);
		crss.push_back(s[i][1]);
	}
	sort(crss.begin(), crss.end());
	crss.erase(unique(crss.begin(), crss.end()), crss.end());

	return make_pair(crss, segment_arrangement(s, crss));
}

pair<int,int> dfs(vector<int>&depths,int de,vector<int>&used,const int now,const int from,vector<int>&prevs,ld &ans, const vector<Point>&ps,const Graph&g) {
	vector<pair<ld,int>>next_points;
	depths[now]=de;
	Point from_p=from==-1?ps[now]+Point(-3e6,0):ps[from];
	Point now_p=ps[now];
	for (auto e : g[now]) {
		if(e.dest==from)continue;
		Point next_p=ps[e.dest];

		ld costheta=dot(from_p-now_p,next_p-now_p)/(abs(from_p-now_p)*abs(next_p-now_p));
		costheta*=0.3;
		ld d=acos(costheta);
		if (ccw(from_p, now_p, next_p) != 1) {
			d=2*pi-d;
		}
		next_points.push_back(make_pair(d,e.dest));
	}
	sort(next_points.begin(),next_points.end());

	int flag=-1;
	for (auto n_p : next_points) {
		if (flag != -1) {
			if (n_p.second == flag) {
				flag=-1;
				continue;
			}
			else {
				continue;
			}
		}
		if (prevs[n_p.second] != -1) {
			Polygon lpoly;
			int rid=now;
			int lid=n_p.second;

			Polygon rpoly;
			while (depths[rid] > depths[lid]) {
				rpoly.push_back(ps[rid]);
				rid=prevs[rid];
			}
			while (depths[rid] < depths[lid]) {
				lpoly.push_back(ps[lid]);
				lid = prevs[lid];
			}
			while (rid != lid) {
				rpoly.push_back(ps[rid]);
				lpoly.push_back(ps[lid]);
				rid=prevs[rid];
				lid=prevs[lid];
			}
			Polygon poly(lpoly);
			poly.push_back(ps[rid]);
			for (int i = 0; i < rpoly.size(); ++i) {
				poly.push_back(rpoly[rpoly.size()-i-1]);
			}
			
			ld plus=get_area(poly);
			ans+=abs(-plus);
			used[now] = true;
			return make_pair(n_p.second,now);
		}
		prevs[n_p.second]=now;
		auto  num=dfs(depths,de+1,used,n_p.second,now,prevs,ans,ps,g);
		prevs[n_p.second]=-1;
		if (num.first != -1) {
			if (num.first == now) {
				flag=num.second;
			}
			else {

				used[now] = true;
				return num;
			}
		}
	}
	//assert(flag==-1);
	used[now]=true;
	return make_pair(-1,-1);
}

int main()
{
	int N;cin>>N;
	vector<Point>ps;
	for (int i = 0; i < N; ++i) {
		int a,b;cin>>a>>b;
		ps.push_back(Point(a,b));
	}
	vector<Line>ls;
	for (int i = 0; i < N - 1; ++i) {
		Line l(ps[i],ps[i+1]);
		ls.emplace_back(l);
	}

	auto p=sennbunn_arrangement(ls);
	ld ans=0;
	vector<int>prevs(p.first.size(),-1);
	prevs[0]=-2;
	vector<int>used(p.first.size(),false);
	vector<int>depths(p.first.size(),-1);
	dfs(depths,0,used,0,-1,prevs,ans,p.first,p.second);
	cout<<setprecision(10)<<fixed<<ans<<endl;
	return 0;
}
accuracy: 0.5357142857142857
time_ms: 10
memory_kb: 3496
final_rank: 16

code_snippet: #include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld=long double;
ld eps=1e-9;
/* 幾何の基本 */

#include <complex>

typedef complex<ld> Point;


const ld pi = acos(-1.0);
const ld dtop = pi / 180.;
const ld ptod = 1. / dtop;

namespace std {
	bool operator<(const Point &lhs, const Point &rhs) {
		if (lhs.real() < rhs.real() - eps) return true;
		if (lhs.real() > rhs.real() + eps) return false;
		return lhs.imag() < rhs.imag();
	}
}

// 点の入力
Point input_Point() {
	ld x, y;
	cin >> x >> y;
	return Point(x, y);
}

// 誤差つき等号判定
bool eq(const ld a, const ld b) {
	return (abs(a - b) < eps);
}

// 内積
ld dot(const Point& a, const Point& b) {
	return real(conj(a) * b);
}

// 外積
ld cross(const Point& a, const Point& b) {
	return imag(conj(a) * b);
}

// 直線の定義
class Line {
public:
	Point a, b;
	Line() : a(Point(0, 0)), b(Point(0, 0)) {}
	Line(Point a, Point b) : a(a), b(b) {}
	Point operator[](const int _num)const {
		if (_num == 0)return a;
		else if (_num == 1)return b;
		else {
			assert(false);
			return Point();
		}
	}
};

// 円の定義
class Circle {
public:
	Point p;
	ld r;
	Circle() : p(Point(0, 0)), r(0) {}
	Circle(Point p, ld r) : p(p), r(r) {}
};

// ccw
// 1: a,b,cが反時計周りの順に並ぶ
//-1: a,b,cが時計周りの順に並ぶ
// 2: c,a,bの順に直線に並ぶ
//-2: a,b,cの順に直線に並ぶ
// 0: a,c,bの順に直線に並ぶ
int ccw(const Point& a, const Point &b, const Point &c) {
	const Point nb(b - a);
	const Point nc(c - a);
	if (cross(nb, nc) > eps) return 1;   // a,b,cが反時計周りの順に並ぶ
	if (cross(nb, nc) < -eps) return -1; // a,b,cが時計周りの順に並ぶ
	if (dot(nb, nc) < 0) return 2;       // c,a,bの順に直線に並ぶ
	if (norm(nb) < norm(nc)) return -2;  // a,b,cの順に直線に並ぶ
	return 0;                          // a,c,bの順に直線に並ぶ
}


/* 交差判定 */

// 直線と直線の交差判定
bool isis_ll(const Line& l, const Line& m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}

// 直線と線分の交差判定
bool isis_ls(const Line& l, const Line& s) {
	return isis_ll(l, s) &&
		(cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}

// 線分と線分の交差判定
bool isis_ss(const Line& s, const Line& t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
		ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// 点の直線上判定
bool isis_lp(const Line& l, const Point& p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}

// 点の線分上判定
bool isis_sp(const Line& s, const Point& p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// 垂線の足
Point proj(const Line &l, const Point& p) {
	ld t = dot(p - l.a, l.b - l.a) / norm(l.a - l.b);
	return l.a + t * (l.b - l.a);
}

//線対象の位置にある点
Point reflect(const Line &l, const Point &p) {
	Point pr = proj(l, p);
	return pr * 2.l - p;
}

// 直線と直線の交点
Point is_ll(const Line &s, const Line& t) {
	Point sv = s.b - s.a, tv = t.b - t.a;
	assert(cross(sv, tv) != 0);
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
// 直線と直線の交点
vector<Point> is_ll2(const Line &s, const Line& t) {
	Point sv = s.b - s.a, tv = t.b - t.a;
	if (cross(sv, tv) != 0)return vector<Point>(1, is_ll(s, t));
	else {
		vector<Point>ans;
		for (int k = 0; k < 2; ++k) {
			if (isis_sp(s, t[k]) && find(ans.begin(), ans.end(), t[k]) == ans.end())ans.push_back(t[k]);
			if (isis_sp(t, s[k]) && find(ans.begin(), ans.end(), s[k]) == ans.end())ans.push_back(s[k]);
		}
		return ans;
	}
}
// 線分と線分の交点
//　重なってる部分あるとassert(false)
Point is_ss(const Line &s, const Line& t) {
	if (isis_ss(s, t)) {
		for (int k = 0; k < 2; ++k) {
			for (int l = 0; l < 2; ++l) {
				if (s[k] == t[l])return s[k];
			}
		}
		return is_ll(s, t);
	}
	else {
		//先にisis_ssしてね
		assert(false);
		return Point(0, 0);
	}
}
// 線分と線分の交点
vector<Point> is_ss2(const Line &s, const Line& t) {
	vector<Point> kouho(is_ll2(s, t));
	vector<Point>ans;
	for (auto p : kouho) {
		if (isis_sp(s, p) && isis_sp(t, p))ans.emplace_back(p);
	}
	return ans;
}
// 直線と点の距離
ld dist_lp(const Line& l, const Point& p) {
	return abs(p - proj(l, p));
}

//直線と直線の距離
ld dist_ll(const Line& l, const Line& m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}

// 直線と線分の距離
ld dist_ls(const Line& l, const Line& s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}

// 線分と点の距離
ld dist_sp(const Line& s, const Point& p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(r - p) : min(abs(s.a - p), abs(s.b - p));
}

// 線分と線分の距離
ld dist_ss(const Line& s, const Line& t) {
	if (isis_ss(s, t)) return 0;
	return min({ dist_sp(s, t.a), dist_sp(s, t.b), dist_sp(t, s.a), dist_sp(t, s.b) });
}


//直線と直線の二等分線のベクトル
Line line_bisection(const Line &s, const Line &t) {
	const Point laglanju(is_ll(s, t));
	const Point avec = !(abs(laglanju - s[0])<eps) ? s[0] - laglanju : s[1] - laglanju;
	const Point bvec = !(abs(laglanju - t[0])<eps) ? t[0] - laglanju : t[1] - laglanju;

	return Line(laglanju, laglanju + (abs(bvec)*avec + abs(avec)*bvec) / (abs(avec) + abs(bvec)));
}
//点と点の垂直二等分線　aを左に見ながら
Line point_bisection(const Point&a, const Point&b) {
	const Point cen((a + b) / 2.l);
	const Point vec = (b - a)*Point(0, 1);
	return Line(cen, cen + vec);
}

//三つの点からなる外心
Point outer_center(const vector<Point>&ps) {
	assert(ps.size() == 3);
	Line l1 = point_bisection(ps[0], ps[1]);
	Line l2 = point_bisection(ps[1], ps[2]);
	return is_ll(l1, l2);
}


//三つの直線からなる内心
//三つの直線が並行でないことは確かめといてね
Point  inner_center(const vector<Line>&ls) {
	vector<Point>vertics;
	for (int i = 0; i <static_cast<int>(ls.size()); ++i) {
		vertics.push_back(is_ll(ls[i], ls[(i + 1) % 3]));
	}
	if (vertics[0] == vertics[1] || vertics[1] == vertics[2] || vertics[2] == vertics[0])return vertics[0];
	Line bi1(line_bisection(Line(vertics[0], vertics[1]), Line(vertics[0], vertics[2])));
	Line bi2(line_bisection(Line(vertics[1], vertics[2]), Line(vertics[1], vertics[0])));
	if (bi1[0] == bi2[0])return bi1[0];
	else {
		return is_ll(bi1, bi2);
	}
}

//三つの直線からなる傍心
//三つの直線が並行でないことは確かめといてね
vector<Point>  ex_center(const vector<Line>&ls) {
	vector<Point>vertics;
	for (int i = 0; i < static_cast<int>(ls.size()); ++i) {
		vertics.push_back(is_ll(ls[i], ls[(i + 1) % 3]));
	}
	if (abs(vertics[0] - vertics[1])<eps || abs(vertics[1] - vertics[2])<eps || (abs(vertics[2] - vertics[0])<eps))return vector<Point>();
	vector<Point>ecs;
	for (int i = 0; i < 3; ++i) {
		Line bi1(line_bisection(Line(vertics[i], vertics[i] * 2.0l - vertics[(i + 2) % 3]), Line(vertics[i], vertics[(i + 1) % 3])));
		Line bi2(line_bisection(Line(vertics[(i + 1) % 3], vertics[(i + 1) % 3] * 2.0l - vertics[(i + 2) % 3]), Line(vertics[(i + 1) % 3], vertics[i])));
		ecs.push_back(is_ll(bi1, bi2));
	}
	return ecs;
}


//a,b:並行
//c:並行でない
//三つの直線から同距離の位置を求める。
vector<Point>  same_dis(const vector<Line>&ls) {
	vector<Point>vertics;
	vertics.push_back(is_ll(ls[0], ls[2]));
	vertics.push_back(is_ll(ls[1], ls[2]));

	if (abs(vertics[0] - vertics[1]) < eps)return vector<Point>{vertics[0]};
	Line bis(line_bisection(ls[0], ls[1]));
	vector<Point>ecs;

	Line abi(line_bisection(Line(vertics[0], vertics[1]), ls[0]));
	ecs.push_back(is_ll(bis, abi));


	Line bbi(line_bisection(Line(vertics[0], 2.l*vertics[0] - vertics[1]), ls[0]));
	ecs.push_back(is_ll(bis, bbi));

	return ecs;
}
/* 円 */

// 円と円の交点
vector<Point> is_cc(const Circle& c1, const Circle& c2) {
	vector<Point> res;
	ld d = abs(c1.p - c2.p);
	ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
	ld dfr = c1.r * c1.r - rc * rc;
	if (abs(dfr) < eps) dfr = 0.0;
	else if (dfr < 0.0) return res; // no intersection
	ld rs = sqrt(dfr);
	Point diff = (c2.p - c1.p) / d;
	res.push_back(c1.p + diff * Point(rc, rs));
	if (dfr != 0.0) res.push_back(c1.p + diff * Point(rc, -rs));
	return res;
}

/*
点が円の中にいるか
0 => out
1 => on
2 => in*/
int is_in_Circle(const  Point& p, const Circle &cir) {
	ld dis = abs(cir.p - p);
	if (dis > cir.r + eps)return 0;
	else if (dis < cir.r - eps)return 2;
	else return 1;
}
int is_in_Circle(const Circle &cir, const  Point& p) {
	ld dis = abs(cir.p - p);
	if (dis > cir.r + eps)return 0;
	else if (dis < cir.r - eps)return 2;
	else return 1;
}
/*
円lcが円rcの中にいるか
0 => out
1 => on
2 => in*/
int Circle_in_Circle(const Circle &lc, const  Circle&rc) {
	ld dis = abs(lc.p - rc.p);
	if (dis < rc.r - lc.r - eps)return 2;
	else if (dis>rc.r - lc.r + eps)return 0;
	else return 1;
}

// 円と直線の交点
vector<Point> is_lc(const Circle& c, const Line& l) {
	vector<Point> res;
	ld d = dist_lp(l, c.p);
	if (d < c.r + eps) {
		ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
		Point nor = (l.a - l.b) / abs(l.a - l.b);
		res.push_back(proj(l, c.p) + len * nor);
		res.push_back(proj(l, c.p) - len * nor);
	}
	return res;
}

// 円と線分の距離
vector<Point> is_sc(const Circle& c, const Line& l) {
	vector<Point> v = is_lc(c, l), res;
	for (Point p : v)
		if (isis_sp(l, p)) res.push_back(p);
	return res;
}

// 円と点の接線
vector<Line> tangent_cp(const Circle& c, const Point& p) {
	vector<Line> ret;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r * c.r);
	if (isnan(l)) { return ret; }
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	ret.push_back(Line(p, p + v1));
	if (l < eps) return ret;
	ret.push_back(Line(p, p + v2));
	return ret;
}

// 円と円の接線
vector<Line> tangent_cc(const Circle& c1, const Circle& c2) {
	vector<Line> ret;
	if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
		Point center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
		ret = tangent_cp(c1, center);
	}
	if (abs(c1.r - c2.r) > eps) {
		Point out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
		vector<Line> nret = tangent_cp(c1, out);
		ret.insert(ret.end(), nret.begin(), nret.end());
	}
	else {
		Point v = c2.p - c1.p;
		v /= abs(v);
		Point q1 = c1.p + v * Point(0, 1) * c1.r;
		Point q2 = c1.p + v * Point(0, -1) * c1.r;
		ret.push_back(Line(q1, q1 + v));
		ret.push_back(Line(q2, q2 + v));
	}
	return ret;
}
//二つの円の重なり面積
ld two_Circle_area(const Circle&l, const Circle&r) {
	ld dis = abs(l.p - r.p);
	if (dis > l.r + r.r)return 0;
	else if (dis + r.r < l.r) {
		return r.r*r.r*pi;
	}
	else if (dis + l.r < r.r) {
		return l.r*l.r*pi;
	}
	else {
		ld ans = (l.r)*(l.r)*acos((dis*dis + l.r*l.r - r.r*r.r) / (2 * dis*l.r)) +
			(r.r)*(r.r)*acos((dis*dis + r.r*r.r - l.r*l.r) / (2 * dis*r.r)) -
			sqrt(4 * dis*dis*l.r*l.r - (dis*dis + l.r*l.r - r.r*r.r)*(dis*dis + l.r*l.r - r.r*r.r)) / 2;
		return ans;
	}

}

/* 多角形 */

typedef vector<Point> Polygon;



//多角形(複数の点)の最小包含円をO(N=頂点数)で求めるアルゴリズム
//同一直線上に三つの点がないこと
#include<random>
Circle welzl(vector<Point>ps) {
	struct solver {
		Circle solve(vector<Point>&ps, vector<Point>&rs) {
			if (ps.empty() || rs.size() == 3) {
				if (rs.size() == 1) {
					return Circle(Point(rs[0]), 0);
				}
				else if (rs.size() == 2) {
					return Circle((rs[0] + rs[1]) / 2.0l, abs(rs[1] - rs[0]) / 2);
				}
				else if (rs.size() == 3) {
					vector<Line> ls(3);
					for (int i = 0; i < 3; ++i) {
						ls[i] = Line(rs[i], rs[(i + 1) % 3]);
					}
					Point center = outer_center(rs);
					return Circle(center, abs(center - rs[0]));
				}
				else {
					return Circle(Point(), 0);
				}
			}
			else {

				Point p_ba = ps.back();
				ps.pop_back();
				Circle d = solve(ps, rs);
				ps.push_back(p_ba);
				if (is_in_Circle(d, p_ba)) {
					return d;
				}
				else {
					rs.push_back(p_ba);
					ps.pop_back();
					auto ans = solve(ps, rs);
					ps.push_back(p_ba);
					rs.pop_back();
					return ans;
				}
			}
		}
	}so;
	std::random_device rd;
	std::mt19937 mt(rd());
	shuffle(ps.begin(), ps.end(), mt);
	vector<Point>rs;
	Circle ans = so.solve(ps, rs);
	return ans;
}
// 面積
ld get_area(const Polygon &p) {
	ld res = 0;
	int n = p.size();
	for (int j = 0; j<n; ++j) res += cross(p[j], p[(j + 1) % n]);
	return res / 2;
}

//多角形の回転方向
bool is_counter_clockwise(const Polygon &poly) {
	ld angle = 0;
	int n = poly.size();
	for(int i=0;i<n;++i) {
		Point a = poly[i], b = poly[(i + 1) % n], c = poly[(i + 2) % n];
		angle += arg((c - b) / (b - a));
	}
	return angle > eps;
}

// 円の内外判定
/*0 => out
1 => on
2 => in*/
int is_in_Polygon(const Polygon &poly, const  Point& p) {
	ld angle = 0;
	int n = poly.size();
	for(int i=0;i<n;++i) {
		Point a = poly[i], b = poly[(i + 1) % n];
		if (isis_sp(Line(a, b), p)) return 1;
		angle += arg((b - p) / (a - p));
	}
	return eq(angle, 0) ? 0 : 2;
}
//円の内外判定2　高速
enum { out, on, in };
int convex_contains(const Polygon &P, const Point &p) {
	const int n = P.size();
	Point g = (P[0] + P[n / 3] + P[2 * n / 3]) / 3.0l; // inner-point
	int a = 0, b = n;
	while (a + 1 < b) { // invariant: c is in fan g-P[a]-P[b]
		int c = (a + b) / 2;
		if (cross(P[a] - g, P[c] - g) > 0) { // angle < 180 deg
			if (cross(P[a] - g, p - g) > 0 && cross(P[c] - g, p - g) < 0) b = c;
			else                                                  a = c;
		}
		else {
			if (cross(P[a] - g, p - g) < 0 && cross(P[c] - g, p - g) > 0) a = c;
			else                                                  b = c;
		}
	}
	b %= n;
	if (cross(P[a] - p, P[b] - p) < 0) return 0;
	if (cross(P[a] - p, P[b] - p) > 0) return 2;
	return 1;
}

// 凸包
//点や線を返すことも有り得るので注意
Polygon convex_hull(vector<Point> ps) {
	int n = ps.size();
	int k = 0;
	sort(ps.begin(), ps.end());
	Polygon ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++])
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--])
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}



//凸カット
vector<Polygon> convex_cut(const Polygon &ps, const Line& l) {
	int n = ps.size();
	Polygon q;
	Polygon r;
	for(int i=0;i<n;++i) {
		Point a = ps[i], b = ps[(i + 1) % n];
		Line m = Line(a, b);
		if (ccw(l.a, l.b, a) != -1) q.push_back(a);
		if (ccw(l.a, l.b, a) != 1) r.push_back(a);
		if (ccw(l.a, l.b, a) * ccw(l.a, l.b, b) < 0 && isis_ll(l, m)) {
			q.push_back(is_ll(l, m));
			r.push_back(is_ll(l, m));
		}
	}
	const vector<Polygon>polys{ q,r };
	return polys;
}


/* アレンジメント */
void add_Point(vector<Point> &ps, const Point p) {
	for (Point q : ps) if (abs(q - p) < eps) return;
	ps.push_back(p);
}


struct Edge {
	int src;
	int dest;
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

void add_edge(Graph &g, int src, int dest) {
	g[src].push_back(Edge{ src, dest});
	g[dest].push_back(Edge{ dest, src});
}

Graph segment_arrangement(const vector<Line> &s, const vector<Point> &p) {
	int n = p.size(), m = s.size();
	Graph g(n);
	for(int i=0;i<m;++i){
		vector<pair<ld, int>> vec;
		for(int j=0;j<n;++j){
			if (isis_sp(s[i], p[j]))
				vec.emplace_back(abs(s[i].a - p[j]), j);
		}
		sort(vec.begin(),vec.end());
		for(int j=0;j<vec.size()-1;++j) {
			int from = vec[j].second, to = vec[j + 1].second;
			
			if (find_if(g[from].begin(), g[from].end(), [&](const Edge&e) {
				return e.dest == to; })==g[from].end())add_edge(g, from, to);
			
		}
	}
	return g;
}
pair<vector<Point>, Graph> sennbunn_arrangement(const vector<Line>&s) {
	vector<Point>crss;
	for (int i = 0; i < static_cast<int>(s.size()); ++i) {
		for (int j = i + 1; j < static_cast<int>(s.size()); ++j) {
			if (isis_ss(s[i], s[j])) {
				crss.push_back(is_ll2(s[i], s[j])[0]);
			}
		}
	}
	for (int i = 0; i <static_cast<int>(s.size()); ++i) {
		crss.push_back(s[i][0]);
		crss.push_back(s[i][1]);
	}
	sort(crss.begin(), crss.end());
	crss.erase(unique(crss.begin(), crss.end()), crss.end());

	return make_pair(crss, segment_arrangement(s, crss));
}

pair<int,int> dfs(vector<int>&depths,int de,vector<int>&used,const int now,const int from,vector<int>&prevs,ld &ans, const vector<Point>&ps,const Graph&g) {
	vector<pair<ld,int>>next_points;
	depths[now]=de;
	Point from_p=from==-1?Point(-3e6,-3e6):ps[from];
	Point now_p=ps[now];
	for (auto e : g[now]) {
		if(e.dest==from)continue;
		Point next_p=ps[e.dest];

		ld costheta=dot(from_p-now_p,next_p-now_p)/(abs(from_p-now_p)*abs(next_p-now_p));
		costheta*=0.99999;
		ld d=acos(costheta);
		if (ccw(from_p, now_p, next_p) != 1) {
			d=2*pi-d;
		}
		next_points.push_back(make_pair(d,e.dest));
	}
	sort(next_points.begin(),next_points.end());

	int flag=-1;
	for (auto n_p : next_points) {
		if (flag != -1) {
			if (n_p.second == flag) {
				flag=-1;
				continue;
			}
		}
		if (prevs[n_p.second] != -1) {
			Polygon lpoly;
			int rid=now;
			int lid=n_p.second;

			Polygon rpoly;
			while (depths[rid] > depths[lid]) {
				rpoly.push_back(ps[rid]);
				rid=prevs[rid];
			}
			while (depths[rid] < depths[lid]) {
				lpoly.push_back(ps[lid]);
				lid = prevs[lid];
			}
			while (rid != lid) {
				rpoly.push_back(ps[rid]);
				lpoly.push_back(ps[lid]);
				rid=prevs[rid];
				lid=prevs[lid];
			}
			Polygon poly(lpoly);
			poly.push_back(ps[rid]);
			for (int i = 0; i < rpoly.size(); ++i) {
				poly.push_back(rpoly[rpoly.size()-i-1]);
			}
			
			ld plus=get_area(poly);
			ans+=abs(-plus);
			used[now] = true;
			return make_pair(n_p.second,now);
		}
		prevs[n_p.second]=now;
		auto  num=dfs(depths,de+1,used,n_p.second,now,prevs,ans,ps,g);
		prevs[n_p.second]=-1;
		if (num.first != -1) {
			if (num.first == now) {
				flag=num.second;
			}
			else {

				used[now] = true;
				return num;
			}
		}
	}
	//assert(flag==-1);
	used[now]=true;
	return make_pair(-1,-1);
}

int main()
{
	int N;cin>>N;
	vector<Point>ps;
	for (int i = 0; i < N; ++i) {
		int a,b;cin>>a>>b;
		ps.push_back(Point(a,b));
	}
	vector<Line>ls;
	for (int i = 0; i < N - 1; ++i) {
		Line l(ps[i],ps[i+1]);
		ls.emplace_back(l);
	}

	auto p=sennbunn_arrangement(ls);
	ld ans=0;
	vector<int>prevs(p.first.size(),-1);
	prevs[0]=-2;
	vector<int>used(p.first.size(),false);
	vector<int>depths(p.first.size(),-1);
	dfs(depths,0,used,0,-1,prevs,ans,p.first,p.second);
	cout<<setprecision(10)<<fixed<<ans<<endl;
	return 0;
}
accuracy: 0.5
time_ms: 10
memory_kb: 3436
final_rank: 17

code_snippet: // 
// 22 line ???????????????
//
#include <iostream>
#include <vector>
#include <cstdio>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <map>
#include <cassert>
#include <queue>
#include <set>
#include <functional>
#include <ctime>
#include <numeric>

using namespace std;

#define fst first
#define snd second
#define all(c) ((c).begin()), ((c).end())
#define TEST(x,a) { auto y=(x); if (sign(y-a)) { cout << "line " << __LINE__  << #x << " = " << y << " != " << a << endl; exit(-1); } }

#define dout if(0)cout

double urand() { return rand() / (1.0 + RAND_MAX); }

const double PI = acos(-1.0);

// implementation note: use EPS only this function
// usage note: check sign(x) < 0, sign(x) > 0, or sign(x) == 0
// notice: should be normalize to O(1)
const double EPS = 1e-8;
int sign(double x) {
  if (x < -EPS) return -1;
  if (x > +EPS) return +1;
  return 0;
}
struct point {
  typedef double T;
  T x, y; 
  point &operator+=(point p) { x += p.x; y += p.y; return *this; }
  point &operator*=(T a)     { x *= a;   y *= a;   return *this; }
  point &operator-=(point p) { x -= p.x; y -= p.y; return *this; }
  point &operator/=(T a)     { return *this *= (1.0/a); }
  point operator-() const    { return {-x, -y}; }
  bool operator<(point p) const { 
    if (sign(x - p.x)) return sign(x - p.x) < 0;
    return sign(y - p.y) < 0;
  }
};
bool operator>(point p, point q) { return q<p; }
bool operator<=(point p, point q) { return !(q<p); }
bool operator>=(point p, point q) { return !(p<q); }
bool operator==(point p, point q) { return !(p<q) && !(q<p); }
bool operator!=(point p, point q) { return (p<q) || !(q<p); }
point operator+(point p, point q) { return p += q; }
point operator-(point p, point q) { return p -= q; }
point operator*(point::T a, point p) { return p *= a; }
point operator*(point p, point::T a) { return p *= a; }
point operator/(point p, point::T a) { return p /= a; }
point::T dot(point p, point q) { return p.x*q.x+p.y*q.y; }
point::T cross(point p, point q) { return p.x*q.y-p.y*q.x; } // left turn > 0
point::T norm2(point p) { return dot(p,p); }
point orth(point p) { return {-p.y, p.x}; }
point::T norm(point p) { return sqrt(dot(p,p)); }

int sign_dot(point p, point q) {
  double a = norm(p), b = norm(q);
  if (sign(a) == 0 || sign(b) == 0) return 0;
  return sign(dot(p, q)/a/b);
}
int sign_cross(point p, point q) {
  double a = norm(p), b = norm(q);
  if (sign(a) == 0 || sign(b) == 0) return 0;
  return sign(cross(p, q)/a/b);
}

ostream &operator<<(ostream &os, const point &p) { os<<"("<<p.x<<","<<p.y<<")"; return os; }

struct segment { point p, q; };

// s.p + A (s.q - s.p) == t.p + B (t.q - t.p)
// A (s.q - s.p) == t.p - s.p + B (t.q - t.p)
// A = (t.p - s.p)x(t.q - t.p)/(s.q - s.p)x(t.q - t.p)
//

vector<point> intersect(segment s, segment t) {
  auto a = cross(s.q - s.p, t.q - t.p);
  auto b = cross(t.p - s.p, t.q - t.p); 
  auto c = cross(s.q - s.p, s.p - t.p);
  if (a < 0) { a = -a; b = -b; c = -c; }
  if (sign(b) < 0 || sign(a-b) < 0 ||
      sign(c) < 0 || sign(a-c) < 0) return {};      // disjoint
  if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing
  vector<point> ps;                                 // same line
  auto insert_if_possible = [&](point p) {
    for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return;
    ps.push_back(p);
  };
  if (sign(dot(s.p-t.p, s.q-t.p)) <= 0) insert_if_possible(t.p);
  if (sign(dot(s.p-t.q, s.q-t.q)) <= 0) insert_if_possible(t.q);
  if (sign(dot(t.p-s.p, t.q-s.p)) <= 0) insert_if_possible(s.p);
  if (sign(dot(t.p-s.q, t.q-s.q)) <= 0) insert_if_possible(s.q);
  return ps;
}

/*
  struct Face {
    Edge *edge; // Any edge incident to this face (CCW)
    vector<point> ps; 
  };
*/

//
// Verified: AOJ1226
//
struct arrangement {
  // Doubly Connected Edge List, aka., DCEL
  struct Vertex; struct Edge;
  struct Vertex {
    point p;    // 
    Edge *edge; // any edge incident to this vertex
  };
  struct Edge { 
    Vertex *vertex;    // origin vertex of the edge
    Edge *twin;        // reverse edge of e
    Edge *prev, *next; // surrounding edges of face (CCW)
  };
  vector<Vertex*> vertices;
  vector<Edge*> edges;

  // Segments
  vector<segment> segs;

  // Sweep-Line Structure (RBST)
  struct node {
    int index;
    int size = 1;
    node *left = 0, *right = 0;
  } *root = 0;
  int size(node *x) { return x ? x->size : 0; }
  vector<node> ns;

  node *update(node *x) {
    if (x) x->size = 1 + size(x->left) + size(x->right);
    return x;
  }
  node *merge(node *x, node *y) {
    if (!x) return y;
    if (!y) return x;
    if (rand() % (x->size + y->size) < x->size) {
      x->right = merge(x->right, y);
      return update(x);
    } else {
      y->left = merge(x, y->left);
      return update(y);
    }
  }
  template <class C> // 3-way split: cond(x) < 0, cond(x) == 0, cond(x) > 0
  tuple<node*, node*, node*> split(node *x, C cond) {
    if (!x) return make_tuple(x,x,x);
    if (cond(x) == 0) {
      auto a = split(x->left, cond);
      auto b = split(x->right, cond);
      assert(get<2>(a) == 0);
      if (get<0>(b)) {
        cout << "error on processing " << x->index << endl;
        cout << get<0>(b) << " " << get<1>(b) << " " << get<2>(b) << endl;
      }
      assert(get<0>(b) == 0);
      x->left = x->right = 0; update(x);
      get<1>(a) = merge(merge(get<1>(a), x), get<1>(b));
      get<2>(a) = get<2>(b);
      return a;
    }
    if (cond(x) < 0) {
      auto a = split(x->right, cond);
      x->right = 0; update(x);
      get<0>(a) = merge(x, get<0>(a));
      return a;
    }
    if (cond(x) > 0) {
      auto a = split(x->left, cond);
      x->left = 0; update(x);
      get<2>(a) = merge(get<2>(a), x);
      return a;
    }
  }
  template <class F>
  void process(node *x, F func) {
    if (!x) return;
    process(x->left, func);
    func(x);
    process(x->right, func);
  }
  node *leftmost(node *x) { 
    while (x && x->left) x = x->left;
    return x;
  }
  node *rightmost(node *x) {
    while (x && x->right) x = x->right;
    return x;
  }

  set<point> events;
  void display(node *x, int tab = 0) {
    if (!x) return;
    const point &p = *events.begin();
    display(x->left, tab+2);

    auto cond = [&](node *x) {
      const segment &s = segs[x->index];
      //assert(sign(s.p.x - p.x) <= 0);
      //assert(sign(s.q.x - p.x) >= 0);
      if (sign(s.q.x - s.p.x) == 0) {
        if (sign(p.y - s.p.y) < 0) return -1;
        if (sign(s.q.y - p.y) < 0) return +1;
        return 0;
      }
      return -sign_cross(s.p - p, s.q - p);
    };

    dout << string(tab, ' ') << x->index << " (" << segs[x->index].p << "," << segs[x->index].q << ") " << cond(x) << endl;
    display(x->right, tab+2);
  }

  // merge overlapping segments?
  void preprocess() {
    for (int i = 0; i < segs.size(); ++i) {
      if (segs[i].q < segs[i].p) swap(segs[i].p, segs[i].q);
    }
  }
  // ??? uniqueness ?????????????????§?????? uniqueness ??§???
  arrangement(vector<segment> segs_) : segs(segs_) {
    preprocess();
    ns.resize(segs.size());
    map<point, set<int>> L, R;

    for (int i = 0; i < segs.size(); ++i) {
      dout << i << ": " << segs[i].p << " " << segs[i].q << endl;
    }

    //map<Vertex*, vector<Edge*>> inc;
    map<Vertex*, map<Vertex*, Edge*>> adj;

    for (int i = 0; i < segs.size(); ++i) {
      events.insert(segs[i].p);
      events.insert(segs[i].q);
      L[segs[i].p].insert(i);
      R[segs[i].q].insert(i);
      ns[i].index = i;
    }
    vector<Vertex*> last(segs.size());

    while (!events.empty()) {
      const point p = *events.begin();
      Vertex *u = new Vertex({p});
      vertices.push_back(u);

      dout << "processing " << p << endl;
      display(root);
      events.erase(events.begin());
      
      auto cond = [&](node *x) {
        const segment &s = segs[x->index];
        assert(sign(s.p.x - p.x) <= 0);
        assert(sign(s.q.x - p.x) >= 0);
        if (sign(s.q.x - s.p.x) == 0) {
          dout << "  horizontal segment " << x->index << " is: ";
          if (sign(p.y - s.p.y) < 0) dout << "-1" << endl;
          if (sign(s.q.y - p.y) < 0) dout << "+1" << endl;
          if (sign(p.y - s.p.y) < 0) return -1;
          if (sign(s.q.y - p.y) < 0) return +1;
          dout << "0" << endl;
          return 0;
        }
        // cross ???????????????????????????
        // s.p + t (s.q - s.p) = p
        dout << "  segment " << x->index << " is: ";
        dout << -sign_cross(s.p - p, s.q - p) << endl;
        return -sign_cross(s.p - p, s.q - p);
      };
      auto z = split(root, cond);
      dout << "split: " << get<0>(z) << " " << get<1>(z) << " " << get<2>(z) << endl;
      vector<node*> inserter;
      dout << "segments on " << p << ":";
      process(get<1>(z), [&](node *x) {
        dout << " " << x->index;
        Vertex *v = last[x->index];
        assert(v != 0);
        if (!adj[u][v]) {
          adj[u][v] = new Edge({u});
          adj[v][u] = new Edge({v});
          adj[u][v]->twin = adj[v][u];
          adj[v][u]->twin = adj[u][v];
          edges.push_back(adj[u][v]);
          edges.push_back(adj[v][u]);
        }
        /*
        Edge *e = new Edge({u}), *r = new Edge({v});
        e->twin = r; r->twin = e;
        edges.push_back(e);
        edges.push_back(r);
        inc[u].push_back(e);
        inc[v].push_back(r);
        */
        if (!R[p].count(x->index)) 
          inserter.push_back(x);
      });
      dout << endl;
      for (int i: L[p]) {
        if (!R[p].count(i))
          inserter.push_back(&ns[i]);
      }
      sort(all(inserter), [&](node *x, node *y) {
        // x ??????????????????????°??????? ==> x -> y ??? ccw order
        // order at (p + epsilon) ??§?????????; 
        // we can assume that the segments contain p
        // ==> ??????????????§??????
        //
        const segment &s = segs[x->index], &t = segs[y->index];
        return sign_cross(s.q - s.p, t.q - t.p) >= 0;
      });
      auto add_event = [&](node *x, node *y) {
        if (!x || !y) return;
        dout << "add event, p = " << p << endl;
        vector<point> ps = intersect(segs[x->index], segs[y->index]);
        for (point q: ps) {
          dout << "crosspoint of " << x->index << " and " << y->index << " is " << q << endl;
          if (p < q) {
            dout << " ==> inserted" << endl;
            events.insert(q);
          } else {
            dout << " ==> ignored (" << p << " vs " << q << ") = " << (p < q) << endl;
          }
        }
        return;
      };
      if (inserter.empty()) {
        add_event(rightmost(get<0>(z)), leftmost(get<2>(z)));
      } else {
        add_event(rightmost(get<0>(z)), inserter[0]);
        add_event(leftmost(get<2>(z)), inserter.back());
      }
      root = 0;
      for (int i = 0; i < inserter.size(); ++i) {
        last[inserter[i]->index] = u;
        dout << "insert " << inserter[i]->index << endl;
        inserter[i]->left = inserter[i]->right = 0;
        root = merge(root, update(inserter[i]));
      }
      root = merge(merge(get<0>(z), root), get<2>(z));
    }
    for (auto &pp: adj) {
      Vertex *u = pp.fst;
      vector<Edge*> es;
      for (auto z: pp.snd) es.push_back(z.snd);
      sort(all(es), [&](Edge *e, Edge *f) {
        assert(e->vertex == f->vertex);
        auto quad = [](point p) {
          for (int i = 1; i <= 4; ++i, swap(p.x = -p.x, p.y))
            if (p.x > 0 && p.y >= 0) return i;
          return 0;
        };
        const point p = e->twin->vertex->p - e->vertex->p;
        const point q = f->twin->vertex->p - f->vertex->p;
        if (quad(p) != quad(q)) return quad(p) < quad(q);
        return sign_cross(p, q) > 0;
      });
      //cout << "vertex " << u->p << endl;
      u->edge = es.back();
      for (Edge *e: es) {
        //cout << "  edge " << e << ": " << e->vertex->p << " " << e->twin->vertex->p << "; " << e->twin << endl;
        u->edge->next = e;
        u->edge->next->prev = u->edge;
        u->edge = u->edge->next;
      }
    }

/*
    for (auto &pp: inc) {
      Vertex *u = pp.fst;
      vector<Edge*> &es = pp.snd;
      sort(all(inc[u]), [&](Edge *e, Edge *f) {
        assert(e->vertex == f->vertex);
        auto quad = [](point p) {
          for (int i = 1; i <= 4; ++i, swap(p.x = -p.x, p.y))
            if (p.x > 0 && p.y >= 0) return i;
          return 0;
        };
        const point p = e->twin->vertex->p - e->vertex->p;
        const point q = f->twin->vertex->p - f->vertex->p;
        if (quad(p) != quad(q)) return quad(p) < quad(q);
        if (sign(cross(p, q))) return sign(cross(p, q)) > 0;
        return cross(p, q) > 0;
      });
      cout << "vertex " << u->p << endl;
      u->edge = es.back();
      for (Edge *e: es) {
        cout << "  edge " << e << ": " << e->vertex->p << " " << e->twin->vertex->p << "; " << e->twin << endl;
        u->edge->next = e;
        u->edge->next->prev = u->edge;
        u->edge = u->edge->next;
      }
    }
    */
  }
};

void AOJ1226() {
  for (int n; ~scanf("%d", &n) && n; ) {
    //cout << n << endl;
    vector<vector<double>> a(4, vector<double>(n));
    for (int k = 0; k < 4; ++k)
      for (int i = 0; i < n; ++i)
        scanf("%lf", &a[k][i]);

    vector<segment> ss = {
      {{0,0},{0,1}},
      {{0,1},{1,1}},
      {{1,1},{1,0}},
      {{1,0},{0,0}}
    };
    for (int i = 0; i < n; ++i) {
      ss.push_back({{a[0][i],0},{a[1][i],1}});
      ss.push_back({{0,a[2][i]},{1,a[3][i]}});
    }
    arrangement arr(ss);

    double result = 0;
    set<arrangement::Edge*> seen;
    for (auto *e: arr.edges) {
      if (seen.count(e)) continue;
      auto *f = e;
      double area = 0;
      do {
        seen.insert(f);
        area += cross(f->vertex->p, f->twin->vertex->p);
        f = f->twin->prev;
      } while (f != e);
      result = max(result, area);
    }
    printf("%.6f\n", result/2);
  }
}
// 
// s.p + a (s.q - s.p) == t.p + b (t.q - t.p)
// ????§£?????????????????????????????\?????°????????? a ???????????? a* ?????????
//

void AOJ2448() {
  int n; scanf("%d", &n);
  vector<point> ps(n);
  for (int i = 0; i < n; ++i)
    scanf("%lf %lf", &ps[i].x, &ps[i].y);
  vector<segment> ss;
  for (int i = 0; i+1 < n; ++i)
    ss.push_back({ps[i], ps[i+1]});
  arrangement arr(ss);

  double result = 0;
  set<arrangement::Edge*> seen;
  for (auto *e: arr.edges) {
    if (seen.count(e)) continue;
    auto *f = e;
    double area = 0;
    do {
      seen.insert(f);
      area += cross(f->vertex->p, f->twin->vertex->p);
      f = f->twin->prev;
    } while (f != e);
    if (area > 0) result += area;
  }
  printf("%.12f\n", result/2);
}

int main() {
  //AOJ1226();
  AOJ2448();
  return 0;
  /*
  for (int seed =0; seed < 10000; ++seed) {
    cout << "seed = " << seed << endl;
    srand(seed);
    int n = 100;
    vector<segment> ss;
    int x = 0, y = 0;
    for (int i = 0; i < n; ++i) {
      int z = rand() % n, w = rand() % n;
      ss.push_back({{x,y},{z,w}});
      x = z; y = w;
      //cout << ss.back().p << " " << ss.back().q << endl;
    }
    arrangement arr(ss);
  }
  */
  /*
  ss.push_back({{0,0},{3,2}});
  ss.push_back({{0,1},{3,1}});
  ss.push_back({{2,0},{2,4}});
  //ss.push_back({{0,3},{3,2}});
  //ss.push_back({{1.5,0},{1.5,4}});
  //
  */

  /*
  auto *v = arr.get({1,1});
  auto *e = v->edge;
  do { 
    cout << e->vertex->p << " -- " << e->twin->vertex->p << endl;
    e = e->next;
  } while (e != v->edge);
  */
}
accuracy: 1
time_ms: 10
memory_kb: 5372
final_rank: 1

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long double LD;
const int maxn=10010;
const int M=1e6+5;
const LD eps=1e-9;
int sgn(LD x){return (x>eps)-(x<-eps);}

struct P{
	LD x,y;
	int id;
	P(){}
	P(LD _x,LD _y):x(_x),y(_y){}
	LD arg(){return atan2(y,x);}
	LD len(){return sqrt(x*x+y*y);}
	void read(){
		double tx,ty;
		scanf("%lf%lf",&tx,&ty);
		x=tx;y=ty;
	}
	
	void print(){
		printf("(%.3f,%.3f)\n",x,y);
	}
}p[maxn];


P operator+(P a,P b){
	return P(a.x+b.x,a.y+b.y);
}
P operator-(P a,P b){
	return P(a.x-b.x,a.y-b.y);
}
P operator*(P a,LD b){
	return P(a.x*b,a.y*b);
}
P operator/(P a,LD b){
	return P(a.x/b,a.y/b);
}
LD operator^(P a,P b){
	return a.x*b.x+a.y*b.y;
}
LD operator*(P a,P b){
	return a.x*b.y-a.y*b.x;
}
LD det(P a,P b,P c){
	return (b-a)*(c-a);
}

LD dis(P a,P b){
	return (b-a).len();
}
P st;
bool cmp(P a,P b){
	return dis(st,a)<dis(st,b);
}

bool operator<(P a,P b){
	return sgn(a.x-b.x) ? sgn(a.x-b.x)<0 : sgn(a.y-b.y)<0;
}
bool operator==(P a,P b){
	return sgn(a.x-b.x)==0 and sgn(a.y-b.y)==0;
}
int n;


struct L{
	P a,b;
	L(){}
	L(P a,P b):a(a),b(b){}
};
bool onLine(P p,L l){
	return sgn((l.a-p)*(l.b-p))==0;
}
bool onSeg(P p,L s){
	return onLine(p,s) and sgn((p-s.a)^(p-s.b))<=0;
}
bool parallel(L l1,L l2){
	return sgn((l1.a-l1.b)*(l2.a-l2.b))==0;
}
int dir(P p,L l){
	int t=sgn((p-l.b)*(l.b-l.a));
	if(t<0)return -1;
	if(t>0)return 1;
	return 0;
}
P intersect(L l1,L l2){
	LD s1=det(l1.a,l1.b,l2.a);
	LD s2=det(l1.a,l1.b,l2.b);
	return (l2.a*s2-l2.b*s1)/(s2-s1);
}
bool segIntersect(L l1,L l2){
	if(dir(l2.a,l1)*dir(l2.b,l1)<0 && dir(l1.a,l2)*dir(l1.b,l2)<0)
		return true;
	return false;
}
struct edgelist{
	int other[M],succ[M],last[M],sum;
	void clear(){
		memset(last,-1,sizeof last);
		sum=0;
	}
	set<pair<int,int> >S;
	void addEdge(int a,int b){
		if(a>b)swap(a,b);
		if(S.count(make_pair(a,b)))return ;
		S.insert(make_pair(a,b));
	//cerr<<a<<" "<<b<<endl;
		other[sum]=b;succ[sum]=last[a];last[a]=sum++;
		other[sum]=a;succ[sum]=last[b];last[b]=sum++;
	}
}e;

vector<pair<int,LD> >vecs;
vector<int>ee[M];
vector<pair<LD,pair<int,int> > >edges;
int nxt[M],vis[M];
int main(){
	scanf("%d",&n);
	
	
	for(int i=1;i<=n;i++){
		p[i].read();
		p[i].id=i;
	}
	int m=n;
	e.clear();
	
	int sz=0;
	static P pt[M];
	
	for(int i=1;i<n;i++){
		pt[++sz]=p[i];
		for(int j=i+1;j<n;j++){
			L l1=L(p[i],p[i+1]);
			L l2=L(p[j],p[j+1]);
			if(!parallel(l1,l2)){
				P tmp=intersect(l1,l2);
				pt[++sz]=tmp;
			}
		}
	}
	sort(pt+1,pt+1+sz);
	sz=unique(pt+1,pt+1+sz)-pt-1;
	for(int j=1;j<=sz;j++)pt[j].id=j;
	
	for(int i=1;i<n;i++){
		vector<P>vec;
		L l=L(p[i],p[i+1]);
		for(int j=1;j<=sz;j++){
			if(onSeg(pt[j],l)){
				vec.push_back(pt[j]);
			}
		}
		if(vec.empty())assert(0);
		st=p[i];
		sort(vec.begin(),vec.end(),cmp);
		for(int j=1;j<vec.size();j++)
			e.addEdge(vec[j-1].id,vec[j].id);
	}
	
	
	
	n=sz;
	
	//cerr<<sz<<endl;
	//for(int i=1;i<=sz;i++)
	///	pt[i].print();
	LD ans=0;
	for(int x=1;x<=n;x++){
		vector<pair<LD,int> >pairs;
		for(int i=e.last[x];~i;i=e.succ[i]){
			int y=e.other[i];
			pairs.push_back(make_pair((pt[y]-pt[x]).arg(),i));
		}
		sort(pairs.begin(),pairs.end());
		for(int i=0;i<pairs.size();i++){
			nxt[pairs[(i+1)%pairs.size()].second^1]=pairs[i].second;
		}
	}
	memset(vis,0,sizeof vis);
	LD tot=0;
	int cnt=0;
	for(int start=0;start<e.sum;start++){
		if(vis[start])continue;
		LD total=0;
		int now=start;
		vecs.clear();
		while(!vis[now]){
			vis[now]=1;
			total+=pt[e.other[now^1]]*pt[e.other[now]];
			now=nxt[now];
		}
		cnt++;
		if(now==start&&total>0){
			ans+=total;
		}
	}
	//cerr<<cnt<<endl;
	
	printf("%.10f\n",(double)ans/2);
	
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 35068
final_rank: 15

code_snippet: #include<bits/stdc++.h>
using namespace std;
const int maxn=10010;
const int M=1e6+5;
const double eps=1e-9;
int sgn(double x){return (x>eps)-(x<-eps);}

struct P{
	double x,y;
	int id;
	P(){}
	P(double _x,double _y):x(_x),y(_y){}
	double arg(){return atan2(y,x);}
	double len(){return sqrt(x*x+y*y);}
	void read(){
		scanf("%lf%lf",&x,&y);
	}
	
	void print(){
		printf("(%.3f,%.3f)\n",x,y);
	}
}p[maxn];


P operator+(P a,P b){
	return P(a.x+b.x,a.y+b.y);
}
P operator-(P a,P b){
	return P(a.x-b.x,a.y-b.y);
}
P operator*(P a,double b){
	return P(a.x*b,a.y*b);
}
P operator/(P a,double b){
	return P(a.x/b,a.y/b);
}
double operator^(P a,P b){
	return a.x*b.x+a.y*b.y;
}
double operator*(P a,P b){
	return a.x*b.y-a.y*b.x;
}
double det(P a,P b,P c){
	return (b-a)*(c-a);
}

double dis(P a,P b){
	return (b-a).len();
}
P st;
bool cmp(P a,P b){
	return dis(st,a)<dis(st,b);
}

bool operator<(P a,P b){
	return sgn(a.x-b.x) ? a.x<b.x : a.y<b.y;
}
bool operator==(P a,P b){
	return sgn(a.x-b.x)==0 and sgn(a.y-b.y)==0;
}
int n;


struct L{
	P a,b;
	L(){}
	L(P a,P b):a(a),b(b){}
};
bool onLine(P p,L l){
	return sgn((l.a-p)*(l.b-p))==0;
}
bool onSeg(P p,L s){
	return onLine(p,s) and sgn((s.b-s.a)^(p-s.a))>=0 and sgn((s.a-s.b)^(p-s.b))>=0;
}
bool parallel(L l1,L l2){
	return sgn((l1.a-l1.b)*(l2.a-l2.b))==0;
}
int dir(P p,L l){
	int t=sgn((p-l.b)*(l.b-l.a));
	if(t<0)return -1;
	if(t>0)return 1;
	return 0;
}
P intersect(L l1,L l2){
	double s1=det(l1.a,l1.b,l2.a);
	double s2=det(l1.a,l1.b,l2.b);
	return (l2.a*s2-l2.b*s1)/(s2-s1);
}
bool segIntersect(L l1,L l2){
	if(dir(l2.a,l1)*dir(l2.b,l1)<0 && dir(l1.a,l2)*dir(l1.b,l2)<0)
		return true;
	return false;
}
struct edgelist{
	int other[M],succ[M],last[M],sum;
	void clear(){
		memset(last,-1,sizeof last);
		sum=0;
	}
	set<pair<int,int> >S;
	void addEdge(int a,int b){
		if(a>b)swap(a,b);
		if(S.count(make_pair(a,b)))return ;
		S.insert(make_pair(a,b));
	//cerr<<a<<" "<<b<<endl;
		other[sum]=b;succ[sum]=last[a];last[a]=sum++;
		other[sum]=a;succ[sum]=last[b];last[b]=sum++;
	}
}e;

vector<pair<int,double> >vecs;
vector<int>ee[M];
vector<pair<double,pair<int,int> > >edges;
int nxt[M],vis[M];
int main(){
	scanf("%d",&n);
	
	
	for(int i=1;i<=n;i++){
		p[i].read();
		p[i].id=i;
	}
	int m=n;
	e.clear();
	
	int sz=0;
	static P pt[M];
	
	for(int i=1;i<n;i++){
		for(int j=i+1;j<n;j++){
			L l1=L(p[i],p[i+1]);
			L l2=L(p[j],p[j+1]);
			if(!parallel(l1,l2)){
				P tmp=intersect(l1,l2);
				if(onSeg(tmp,l1)&&onSeg(tmp,l2)){
					pt[++sz]=tmp;
				}
			}
		}
	}
	sort(pt+1,pt+1+sz);
	sz=unique(pt+1,pt+1+sz)-pt-1;
	for(int j=1;j<=sz;j++)pt[j].id=j;
	
	for(int i=1;i<n;i++){
		vector<P>vec;
		L l=L(p[i],p[i+1]);
		for(int j=1;j<=sz;j++){
			if(onSeg(pt[j],l)){
				vec.push_back(pt[j]);
			}
		}
		st=p[i];
		sort(vec.begin(),vec.end(),cmp);
		for(int j=1;j<vec.size();j++)
			e.addEdge(vec[j-1].id,vec[j].id);
	}
	
	
	
	n=sz;
	
	//cerr<<sz<<endl;
	//for(int i=1;i<=sz;i++)
	///	pt[i].print();
	double ans=0;
	for(int x=1;x<=n;x++){
		vector<pair<double,int> >pairs;
		for(int i=e.last[x];~i;i=e.succ[i]){
			int y=e.other[i];
			pairs.push_back(make_pair((pt[y]-pt[x]).arg(),i));
		}
		sort(pairs.begin(),pairs.end());
		for(int i=0;i<pairs.size();i++){
			nxt[pairs[(i+1)%pairs.size()].second^1]=pairs[i].second;
		}
	}
	memset(vis,0,sizeof vis);
	double tot=0;
	for(int start=0;start<e.sum;start++){
		if(vis[start])continue;
		double total=0;
		int now=start;
		vecs.clear();
		while(!vis[now]){
			vis[now]=1;
			total+=pt[e.other[now^1]]*pt[e.other[now]];
			now=nxt[now];
		}
		if(now==start&&total>0){
			ans+=total;
		}
	}
	
	printf("%.10f\n",ans/2);
	
	return 0;
}
accuracy: 0.4107142857142857
time_ms: 10
memory_kb: 34888
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
const int maxn=20010;
const int M=1e6+5;
const double eps=1e-9;
int sgn(double x){return (x>eps)-(x<-eps);}

struct P{
	double x,y;
	int id;
	P(){}
	P(double _x,double _y):x(_x),y(_y){}
	double arg(){return atan2(y,x);}
	double len(){return sqrt(x*x+y*y);}
	void read(){
		scanf("%lf%lf",&x,&y);
	}
	
	void print(){
		printf("(%.3f,%.3f)\n",x,y);
	}
}p[maxn];


P operator+(P a,P b){
	return P(a.x+b.x,a.y+b.y);
}
P operator-(P a,P b){
	return P(a.x-b.x,a.y-b.y);
}
P operator*(P a,double b){
	return P(a.x*b,a.y*b);
}
P operator/(P a,double b){
	return P(a.x/b,a.y/b);
}
double operator^(P a,P b){
	return a.x*b.x+a.y*b.y;
}
double operator*(P a,P b){
	return a.x*b.y-a.y*b.x;
}
double det(P a,P b,P c){
	return (b-a)*(c-a);
}

double dis(P a,P b){
	return (b-a).len();
}
P st;
bool cmp(P a,P b){
	return dis(st,a)<dis(st,b);
}

bool operator<(P a,P b){
	return sgn(a.x-b.x) ? a.x<b.x : a.y<b.y;
}
bool operator==(P a,P b){
	return sgn(a.x-b.x)==0 and sgn(a.y-b.y)==0;
}
int n;


struct L{
	P a,b;
	L(){}
	L(P a,P b):a(a),b(b){}
};
bool onLine(P p,L l){
	return sgn((l.a-p)*(l.b-p))==0;
}
bool onSeg(P p,L s){
	return onLine(p,s) and sgn((s.b-s.a)^(p-s.a))>=0 and sgn((s.a-s.b)^(p-s.b))>=0;
}
bool parallel(L l1,L l2){
	return sgn((l1.a-l1.b)*(l2.a-l2.b))==0;
}
int dir(P p,L l){
	int t=sgn((p-l.b)*(l.b-l.a));
	if(t<0)return -1;
	if(t>0)return 1;
	return 0;
}
P intersect(L l1,L l2){
	double s1=det(l1.a,l1.b,l2.a);
	double s2=det(l1.a,l1.b,l2.b);
	return (l2.a*s2-l2.b*s1)/(s2-s1);
}
bool segIntersect(L l1,L l2){
	if(dir(l2.a,l1)*dir(l2.b,l1)<0 && dir(l1.a,l2)*dir(l1.b,l2)<0)
		return true;
	if(onSeg(l1.a,l2)||onSeg(l1.b,l2)||onSeg(l2.a,l1)||onSeg(l2.b,l1))
		return true;
	return false;
}
struct edgelist{
	int other[M],succ[M],last[M],sum;
	void clear(){
		memset(last,-1,sizeof last);
		sum=0;
	}
	set<pair<int,int> >S;
	void addEdge(int a,int b){
		if(a>b)swap(a,b);
		if(S.count(make_pair(a,b)))return ;
		S.insert(make_pair(a,b));
	//cerr<<a<<" "<<b<<endl;
		other[sum]=b;succ[sum]=last[a];last[a]=sum++;
		other[sum]=a;succ[sum]=last[b];last[b]=sum++;
	}
}e;

vector<pair<int,double> >vecs;
vector<int>ee[M];
vector<pair<double,pair<int,int> > >edges;
int nxt[M],vis[M];
int main(){
	scanf("%d",&n);
	
	
	for(int i=1;i<=n;i++){
		p[i].read();
		p[i].id=i;
	}
	int m=n;
	e.clear();
	
	int sz=0;
	static P pt[M];
	
	for(int i=1;i<n;i++){
		for(int j=i+1;j<n;j++){
			L l1=L(p[i],p[i+1]);
			L l2=L(p[j],p[j+1]);
			if(!parallel(l1,l2)){
				P tmp=intersect(l1,l2);
				if(segIntersect(l1,l2)){
					pt[++sz]=tmp;
				}
			}
		}
	}
	sort(pt+1,pt+1+sz);
	sz=unique(pt+1,pt+1+sz)-pt-1;
	for(int j=1;j<=sz;j++)pt[j].id=j;
	
	for(int i=1;i<n;i++){
		vector<P>vec;
		L l=L(p[i],p[i+1]);
		for(int j=1;j<=sz;j++){
			if(onSeg(pt[j],l)){
				vec.push_back(pt[j]);
			}
		}
		st=p[i];
		sort(vec.begin(),vec.end(),cmp);
		for(int j=1;j<vec.size();j++)
			e.addEdge(vec[j-1].id,vec[j].id);
	}
	
	
	
	n=sz;
	
	//cerr<<sz<<endl;
	//for(int i=1;i<=sz;i++)
	///	pt[i].print();
	double ans=0;
	for(int x=1;x<=n;x++){
		vector<pair<double,int> >pairs;
		for(int i=e.last[x];~i;i=e.succ[i]){
			int y=e.other[i];
			pairs.push_back(make_pair((pt[y]-pt[x]).arg(),i));
		}
		sort(pairs.begin(),pairs.end());
		for(int i=0;i<pairs.size();i++){
			nxt[pairs[(i+1)%pairs.size()].second^1]=pairs[i].second;
		}
	}
	memset(vis,0,sizeof vis);
	double tot=0;
	for(int start=0;start<e.sum;start++){
		if(vis[start])continue;
		double total=0;
		int now=start;
		vecs.clear();
		while(!vis[now]){
			vis[now]=1;
			total+=pt[e.other[now^1]]*pt[e.other[now]];
			now=nxt[now];
		}
		if(now==start&&total>0){
			ans+=total;
		}
	}
	
	printf("%.10f\n",ans/2);
	
	return 0;
}
accuracy: 0.4107142857142857
time_ms: 10
memory_kb: 34924
final_rank: 19

code_snippet: #include <set>
#include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define PII pair<int,int>
#define FOR(i,a,b) for (int i=(a);i<=(b);++i)
#define ROF(i,b,a) for (int i=(b);i>=(a);--i)
typedef long long LL;
inline int read(){
	int x=0,f=1; char ch=getchar();
	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
	while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}

const int MAXN=300005;
const double eps=1e-8,INF=1e20,PI=3.141592653589793238462;
struct list{
	int l,lt[MAXN],nt[MAXN],x[MAXN];
	void clear(){ l=0; memset(lt,0,sizeof(lt)); }
	void addedge(int a,int b){ l++; nt[l]=lt[a]; lt[a]=l; x[l]=b; }
}E;
struct P{
	double x,y;
	P(double xx=0,double yy=0):x(xx),y(yy){}
	double len()const{ return sqrt(x*x+y*y); }
	P operator +(const P &E)const{ return P(x+E.x,y+E.y); }
	P operator -(const P &E)const{ return P(x-E.x,y-E.y); }
	P operator *(const double &f)const{ return P(x*f,y*f); }
	P operator /(const double &f)const{ return P(x/f,y/f); }
	double operator *(const P &E)const{ return x*E.y-E.x*y; }
	double operator ^(const P &E)const{ return x*E.x+y*E.y; }
	bool operator <(const P &E)const{ return (x<E.x)||(x==E.x&&y<E.y); }
}A[MAXN],B[MAXN];
double arctan(P a){ double ret=atan2(a.y,a.x); return (ret<eps ? ret+PI*2:ret); }
inline double dist(P a,P b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); }
inline double dot(P a,P b,P c){ return (a-c)^(b-c); }
inline double cross(P a,P b,P c){ return (a-c)*(b-c); }
struct line{
	double a,b,c;
	line(double aa=0,double bb=0,double cc=0):a(aa),b(bb),c(cc){}
};
inline line get_line(P u,P v){ return line(v.y-u.y,u.x-v.x,v*u); }
P Cramer(line l1,line l2){
	double det=l1.a*l2.b-l1.b*l2.a;
	if (fabs(det)<=eps) return P(INF,INF);
	return P((-l1.c*l2.b+l1.b*l2.c)/det,(-l1.a*l2.c+l1.c*l2.a)/det);
}
double ans;
int n,m,l,a[MAXN],b[MAXN];
int cmp(int x,int y){ return B[x]<B[y]; }
int main(){
	n=read(); E.clear(); l=0;
	FOR(i,1,n) { A[i].x=read(); A[i].y=read(); }
	FOR(i,1,n-1) {
		m=0;
		FOR(j,1,n-1)
		if (j!=i) {
			P D=Cramer(get_line(A[i],A[i+1]),get_line(A[j],A[j+1]));
			if ((D.x-A[i].x)*(D.x-A[i+1].x)>eps||(D.y-A[i].y)*(D.y-A[i+1].y)>eps) continue;
			if ((D.x-A[j].x)*(D.x-A[j+1].x)>eps||(D.y-A[j].y)*(D.y-A[j+1].y)>eps) continue;
			B[a[++m]=++l]=D;
			FOR(k,1,l-1) if (dist(B[k],B[l])<=eps) { l--; a[m]=k; break; }
			//printf("%d %d %d\n",i,j,a[m]);
		}
		B[a[++m]=++l]=A[i];
		FOR(k,1,l-1) if (dist(B[k],B[l])<=eps) { l--; a[m]=k; break; }
		B[a[++m]=++l]=A[i+1];
		FOR(k,1,l-1) if (dist(B[k],B[l])<=eps) { l--; a[m]=k; break; }
		
		sort(a+1,a+1+m,cmp);
		FOR(i,1,m-1)
		if (dist(B[a[i]],B[a[i+1]])>eps) E.addedge(a[i],a[i+1]),E.addedge(a[i+1],a[i]);
	}
	//FOR(i,1,l) printf("%.3lf %.3lf %d\n",B[i].x,B[i].y,i);
	/*FOR(i,1,l) {
		printf("%d:",i);
		for (int k=E.lt[i];k;k=E.nt[k]) printf("%d ",E.x[k]);
		printf("\n");
	}*/
	int x=1,y,z,s;
	double alpha=0,tmp=0;
	FOR(i,2,l) if (B[i]<B[x]) x=i;
	y=E.x[E.lt[x]]; z=s=x;
	for (int i=E.lt[x];i;i=E.nt[i]) {
		int j=E.x[i];
		if (cross(B[j],B[y],B[x])>eps) y=j;
	}
	ans=0;
	while (1) {
		//printf("%d %d %.10lf\n",x,y,alpha);
		ans+=B[x]*B[y];
		if (y==s) break;
		z=x; x=y; y=E.x[E.lt[x]];
		alpha=arctan(B[y]-B[x])-arctan(B[z]-B[x]);
		if (alpha<=eps) alpha+=PI*2;
		for (int i=E.lt[x];i;i=E.nt[i]) {
			int j=E.x[i];
			tmp=arctan(B[j]-B[x])-arctan(B[z]-B[x]);
			if (tmp<=eps) tmp+=PI*2;
			//printf("%d %.10lf %.10lf %.10lf %.5lf %.10lf %.10lf %.5lf\n",j,tmp,(B[j]-B[x]).x,(B[j]-B[x]).y,arctan((B[j]-B[x])),(B[z]-B[x]).x,(B[z]-B[x]).y,arctan((B[z]-B[x])));
			if (tmp<alpha) {
				alpha=tmp;
				y=j;
			}
		}
	}
	printf("%.10lf\n",fabs(ans)/2);
	
	return 0;
}

/*
5
1 1
2 3
3 4
2 5
4 2

*/
accuracy: 1
time_ms: 20
memory_kb: 14180
final_rank: 9

code_snippet: #include<bits/stdc++.h>

using namespace std;

const double EPS = 1e-4, PI = acos(-1), INF = 1e9;

inline bool eq(double a, double b)
{
  return abs(b - a) < EPS;
}

struct Point
{
  double x, y;

  Point() {};

  Point(double x, double y) : x(x), y(y) {};

  Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }

  Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }

  Point operator*(const double b) const { return Point(x * b, y * b); }

  Point operator*(const Point &b) const { return Point(x * b.x - y * b.y, x * b.y + y * b.x); }

  Point operator/(const double b) const { return Point(x / b, y / b); }

  bool operator<(const Point &b) const { return x != b.x ? x < b.x : y < b.y; }

  bool operator==(const Point &b) const { return eq(x, b.x) && eq(y, b.y); }

  double norm() const { return x * x + y * y; }

  double arg() { return atan2(x, y); }

  double abs() const { return sqrt(norm()); }

  Point rotate(double theta) { return Point(cos(theta) * x - sin(theta) * y, sin(theta) * x + cos(theta) * y); }

  Point rotate90() { return Point(-y, x); }

  friend ostream &operator<<(ostream &os, Point &p) { return os << "(" << p.x << "," << p.y << ")"; }

  friend istream &operator>>(istream &is, Point &a) { return is >> a.x >> a.y; }
};


double cross(const Point &a, const Point &b)
{
  return a.x * b.y - a.y * b.x;
}

double dot(const Point &a, const Point &b)
{
  return a.x * b.x + a.y * b.y;
}

int ccw(const Point &a, Point b, Point c)
{
  b = b - a, c = c - a;
  if(cross(b, c) > EPS) return +1;
  if(cross(b, c) < -EPS) return -1;
  if(dot(b, c) < 0) return +2;
  if(b.norm() < c.norm()) return -2;
  return 0;
}

struct Segment
{
  Point a, b;

  Segment() {};

  Segment(Point a, Point b) : a(a), b(b) {};

  friend ostream &operator<<(ostream &os, Segment &p) { return os << "(" << p.a.x << "," << p.a.y << ") to (" << p.b.x << "," << p.b.y << ")"; }

  friend istream &operator>>(istream &is, Segment &a) { return is >> a.a.x >> a.a.y >> a.b.x >> a.b.y; }
};

typedef vector< Point > Polygon;

double Area2(const Polygon &p)
{
  double A = 0;
  for(int i = 0; i < p.size(); ++i) {
    A += cross(p[i], p[(i + 1) % p.size()]);
  }
  return A;
}

bool Intersect(const Segment &s, const Point &p)
{
  return ccw(s.a, s.b, p) == 0;
}

bool Intersect(const Segment &s, const Segment &t)
{
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
         ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

Point Crosspoint(const Segment &l, const Segment &m)
{
  double A = cross(l.b - l.a, m.b - m.a);
  double B = cross(l.b - l.a, l.b - m.a);
  if(abs(A) < EPS && abs(B) < EPS) return m.a; // same line
  return m.a + (m.b - m.a) * B / A;
}

double GetAngle(const Point &a, const Point &b)
{
  double tmp = min(1.0, max(-1.0, dot(a, b) / a.abs() / b.abs()));
  double r = acos(tmp) * 180.0 / PI;
  if(cross(a, b) < -EPS) r = 360 - r;
  return r;
}

bool merge_if_able(Segment &s1, Segment s2)
{
  if(abs(cross(s1.b - s1.a, s2.b - s2.a)) > EPS) return false;
  if(ccw(s1.a, s2.a, s1.b) == 1 ||
     ccw(s1.a, s2.a, s1.b) == -1)
    return false;
  if(ccw(s1.a, s1.b, s2.a) == -2 ||
     ccw(s2.a, s2.b, s1.a) == -2)
    return false;
  s1 = Segment(min(s1.a, s2.a), max(s1.b, s2.b));
  return true;
}

void merge_segments(vector< Segment > &segs)
{
  for(int i = 0; i < segs.size(); i++) {
    if(segs[i].b < segs[i].a) swap(segs[i].a, segs[i].b);
  }
  for(int i = 0; i < segs.size(); i++) {
    for(int j = i + 1; j < segs.size(); j++) {
      if(merge_if_able(segs[i], segs[j])) {
        segs[j--] = segs.back(), segs.pop_back();
      }
    }
  }
}

vector< vector< int > > SegmentArrangement(vector< Segment > &segs, vector< Point > &ps)
{
  vector< vector< int > > g;
  const int N = (int) segs.size();
  for(int i = 0; i < N; i++) {
    ps.emplace_back(segs[i].a);
    ps.emplace_back(segs[i].b);
    for(int j = i + 1; j < N; j++) {
      const Point p1 = segs[i].b - segs[i].a;
      const Point p2 = segs[j].b - segs[j].a;
      if(cross(p1, p2) == 0) continue;
      if(Intersect(segs[i], segs[j])) {
        ps.emplace_back(Crosspoint(segs[i], segs[j]));
      }
    }
  }
  sort(begin(ps), end(ps));
  ps.erase(unique(begin(ps), end(ps)), end(ps));

  const int M = (int) ps.size();
  g.resize(M);
  for(int i = 0; i < N; i++) {
    vector< int > vec;
    for(int j = 0; j < M; j++) {
      if(Intersect(segs[i], ps[j])) {
        vec.emplace_back(j);
      }
    }
    for(int j = 1; j < vec.size(); j++) {
      g[vec[j - 1]].push_back(vec[j]);
      g[vec[j]].push_back(vec[j - 1]);
    }
  }
  return (g);
}

int main()
{
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N;
  cin >> N;
  vector< Segment > segs;

  {
    Point pv;
    for(int i = 0; i < N; i++) {
      Point curr;
      cin >> curr;
      if(i) segs.emplace_back((Segment) {pv, curr});
      pv = curr;
    }
  }

  vector< Point > ps;
  merge_segments(segs);
  auto g = SegmentArrangement(segs, ps);

  Point s(INF, INF);
  int t;
  for(auto &p : ps) s = min(s, p);
  for(int i = 0; i < ps.size(); i++) if(ps[i] == s) t = i;

  Polygon poly;

  function< void(int, int) > dfs = [&](int idx, int par)
  {
    if(idx == t) return;
    pair< double, int > nxt(INF, -1);
    for(auto &to : g[idx]) {
      double arg = GetAngle(ps[par] - ps[idx], ps[to] - ps[idx]);
      if(to == par) arg = 361;
      nxt = min(nxt, make_pair(arg, to));
    }
    poly.emplace_back(ps[idx]);
    dfs(nxt.second, idx);
  };
  double ret = 0;
  for(auto &to : g[t]) {
    poly.push_back(s);
    dfs(to, t);
    ret += max(0.0, Area2(poly));
    poly.clear();
  }
  cout << fixed << setprecision(12) << ret * 0.5 << endl;
}
accuracy: 0.07142857142857142
time_ms: 10
memory_kb: 21684
final_rank: 20