## 1. Abridged problem statement

A convex polygon represents the tent walls, and the lamp is at the origin `(0, 0)` strictly inside it. There are `M` thin shelves, each represented by a segment strictly inside the polygon and not passing through the origin.

A shelf blocks light along all rays from the origin that intersect the shelf. These blocked rays shade the corresponding points on the polygon boundary. Compute the total length of shaded parts of the polygon boundary.

Constraints: `3 ≤ N ≤ 100000`, `0 ≤ M ≤ 100000`.

Output the answer with at least `6` digits after the decimal point.

---

## 2. Detailed editorial

### Key observation

The lamp is at the origin and the tent is a convex polygon containing the origin strictly inside.

For every direction angle `θ`, the ray from the origin in that direction intersects the polygon boundary in exactly one point.

So there is a one-to-one correspondence:

```text
angle θ  <->  point on the wall hit by the ray from origin
```

A wall point is shaded iff the ray from the origin to that point intersects at least one shelf.

Therefore, instead of working directly with polygon boundary points, we work with angular intervals blocked by shelves.

---

### Angular interval blocked by one shelf

A shelf is a segment `AB`.

From the origin, the segment subtends some angular interval between the directions of `A` and `B`.

Let:

```cpp
angle(A) = atan2(A.y, A.x)
angle(B) = atan2(B.y, B.x)
```

Normalize angles into `[0, 2π)`.

The segment does not contain the origin, so the visible angular span is the smaller arc between the two endpoint directions.

We can decide orientation using the cross product:

```cpp
cross = A ^ B
```

- If `cross > 0`, then the counter-clockwise interval from `A` to `B` is the blocked interval.
- If `cross < 0`, then the counter-clockwise interval from `B` to `A` is the blocked interval.
- If `cross == 0`, the segment subtends zero angle, so it contributes zero wall length and can be ignored.

If an interval crosses angle `0`, split it into two intervals:

```text
[start, 2π] and [0, end]
```

After processing all shelves, we have many angular intervals. Sort and merge them to get their union.

---

### Converting an angular interval to wall length

Now we need to compute:

```text
length of polygon boundary corresponding to angles in [l, r]
```

Because the polygon is convex and contains the origin, the order of polygon vertices by polar angle is the same as their cyclic order along the boundary.

So we sort polygon vertices by angle.

Let:

```cpp
bound[i] = angle of vertex i
pref[i] = boundary length from vertex 0 to vertex i
```

For an angle `θ`, we find which polygon edge the ray intersects.

If:

```text
bound[i] <= θ <= bound[i + 1]
```

then the ray hits edge:

```text
poly[i] -> poly[i + 1]
```

We intersect the ray from the origin with this edge and compute the boundary distance from the chosen starting vertex to that hit point.

This gives a monotonic function:

```text
S(θ) = boundary distance from starting vertex to wall point at angle θ
```

Then for an angular interval `[l, r]` not crossing the chosen starting angle:

```text
wall length = S(r) - S(l)
```

---

### Handling cyclic wraparound

The sorted vertices start at some angle:

```cpp
g0 = bound[0]
```

The boundary distance function is naturally defined on `[g0, g0 + 2π]`.

But shelf intervals are in `[0, 2π]`.

For a merged interval `[l, r]`:

1. If it lies completely before `g0`, evaluate it as `[l + 2π, r + 2π]`.
2. If it lies completely after `g0`, evaluate normally.
3. If it contains `g0`, split around the polygon starting point:

```text
[l, g0] and [g0, r]
```

The implementation computes this as:

```cpp
perimeter - S(l + 2π) + S(r)
```

---

### Complexity

Sorting polygon vertices:

```text
O(N log N)
```

Sorting shelf angular intervals:

```text
O(M log M)
```

Each interval contributes constant work except for binary search in `S(θ)`:

```text
O(log N)
```

Overall:

```text
O((N + M) log(N + M))
```

Memory usage:

```text
O(N + M)
```

---

## 3. C++ Solution

```cpp
#include <bits/stdc++.h>
// #include <coding_library/geometry/point.hpp>

using namespace std;

template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}

template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& x) {
    return in >> x.first >> x.second;
}

template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) {
        in >> x;
    }
    return in;
};

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto x: a) {
        out << x << ' ';
    }
    return out;
};

using coord_t = double;

struct Point {
    static constexpr coord_t eps = 1e-9;
    static inline const coord_t PI = acos((coord_t)-1.0);

    coord_t x, y;
    Point(coord_t x = 0, coord_t y = 0) : x(x), y(y) {}

    Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
    Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
    Point operator*(coord_t c) const { return Point(x * c, y * c); }
    Point operator/(coord_t c) const { return Point(x / c, y / c); }

    coord_t operator*(const Point& p) const { return x * p.x + y * p.y; }
    coord_t operator^(const Point& p) const { return x * p.y - y * p.x; }

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

    coord_t norm2() const { return x * x + y * y; }
    coord_t norm() const { return sqrt(norm2()); }
    coord_t angle() const { return atan2(y, x); }

    Point rotate(coord_t a) const {
        return Point(x * cos(a) - y * sin(a), x * sin(a) + y * cos(a));
    }

    Point perp() const { return Point(-y, x); }
    Point unit() const { return *this / norm(); }
    Point normal() const { return perp().unit(); }
    Point project(const Point& p) const {
        return *this * (*this * p) / norm2();
    }
    Point reflect(const Point& p) const {
        return *this * 2 * (*this * p) / norm2() - p;
    }

    friend ostream& operator<<(ostream& os, const Point& p) {
        return os << p.x << ' ' << p.y;
    }
    friend istream& operator>>(istream& is, Point& p) {
        return is >> p.x >> p.y;
    }

    friend int ccw(const Point& a, const Point& b, const Point& c) {
        coord_t v = (b - a) ^ (c - a);
        if(-eps <= v && v <= eps) {
            return 0;
        } else if(v > 0) {
            return 1;
        } else {
            return -1;
        }
    }

    friend bool point_on_segment(
        const Point& a, const Point& b, const Point& p
    ) {
        return ccw(a, b, p) == 0 && p.x >= min(a.x, b.x) - eps &&
               p.x <= max(a.x, b.x) + eps && p.y >= min(a.y, b.y) - eps &&
               p.y <= max(a.y, b.y) + eps;
    }

    friend bool point_in_triangle(
        const Point& a, const Point& b, const Point& c, const Point& p
    ) {
        int d1 = ccw(a, b, p);
        int d2 = ccw(b, c, p);
        int d3 = ccw(c, a, p);
        return (d1 >= 0 && d2 >= 0 && d3 >= 0) ||
               (d1 <= 0 && d2 <= 0 && d3 <= 0);
    }

    friend Point line_line_intersection(
        const Point& a1, const Point& b1, const Point& a2, const Point& b2
    ) {
        return a1 +
               (b1 - a1) * ((a2 - a1) ^ (b2 - a2)) / ((b1 - a1) ^ (b2 - a2));
    }

    friend bool collinear(const Point& a, const Point& b) {
        return abs(a ^ b) < eps;
    }

    friend Point circumcenter(const Point& a, const Point& b, const Point& c) {
        Point mid_ab = (a + b) / 2.0;
        Point mid_ac = (a + c) / 2.0;
        Point perp_ab = (b - a).perp();
        Point perp_ac = (c - a).perp();
        return line_line_intersection(
            mid_ab, mid_ab + perp_ab, mid_ac, mid_ac + perp_ac
        );
    }

    friend coord_t arc_area(
        const Point& center, coord_t r, const Point& p1, const Point& p2
    ) {
        coord_t theta1 = (p1 - center).angle();
        coord_t theta2 = (p2 - center).angle();
        if(theta2 < theta1 - eps) {
            theta2 += 2 * PI;
        }

        coord_t d_theta = theta2 - theta1;
        coord_t cx = center.x, cy = center.y;
        coord_t area = r * cx * (sin(theta2) - sin(theta1)) -
                       r * cy * (cos(theta2) - cos(theta1)) + r * r * d_theta;
        return area / 2.0;
    }

    friend vector<Point> intersect_circles(
        const Point& c1, coord_t r1, const Point& c2, coord_t r2
    ) {
        Point d = c2 - c1;
        coord_t dist = d.norm();

        if(dist > r1 + r2 + eps || dist < abs(r1 - r2) - eps || dist < eps) {
            return {};
        }

        coord_t a = (r1 * r1 - r2 * r2 + dist * dist) / (2 * dist);
        coord_t h_sq = r1 * r1 - a * a;
        if(h_sq < -eps) {
            return {};
        }
        if(h_sq < 0) {
            h_sq = 0;
        }
        coord_t h = sqrt(h_sq);

        Point mid = c1 + d.unit() * a;
        Point perp_dir = d.perp().unit();

        if(h < eps) {
            return {mid};
        }
        return {mid + perp_dir * h, mid - perp_dir * h};
    }

    friend optional<Point> intersect_ray_segment(
        const Point& ray_start, const Point& ray_through, const Point& seg_a,
        const Point& seg_b
    ) {
        Point ray_dir = ray_through - ray_start;
        if(ray_dir.norm2() < Point::eps) {
            return {};
        }
        Point seg_dir = seg_b - seg_a;
        coord_t denom = ray_dir ^ seg_dir;
        if(fabs(denom) < eps) {
            return {};
        }
        coord_t t = ((seg_a - ray_start) ^ seg_dir) / denom;
        if(t < eps) {
            return {};
        }
        coord_t s = ((seg_a - ray_start) ^ ray_dir) / denom;
        if(s < eps || s > 1 - eps) {
            return {};
        }
        return ray_start + ray_dir * t;
    }
};

namespace fastin {
const int BUF = 1 << 16;
char buf[BUF];
int pos = 0, len = 0;

char gc() {
    if(pos == len) {
        len = (int)fread(buf, 1, BUF, stdin);
        pos = 0;
        if(len == 0) {
            return -1;
        }
    }
    return buf[pos++];
}

int64_t read_int() {
    char c = gc();
    while(c != '-' && (c < '0' || c > '9')) {
        c = gc();
    }
    bool neg = c == '-';
    if(neg) {
        c = gc();
    }
    int64_t x = 0;
    while(c >= '0' && c <= '9') {
        x = x * 10 + (c - '0');
        c = gc();
    }
    return neg ? -x : x;
}
}  // namespace fastin

int n, m;
vector<Point> poly;
vector<pair<Point, Point>> shelves;

void read() {
    n = fastin::read_int();
    m = fastin::read_int();
    poly.resize(n);
    for(auto& p: poly) {
        p.x = fastin::read_int();
        p.y = fastin::read_int();
    }
    shelves.resize(m);
    for(auto& [a, b]: shelves) {
        a.x = fastin::read_int();
        a.y = fastin::read_int();
        b.x = fastin::read_int();
        b.y = fastin::read_int();
    }
}

void solve() {
    // The lamp at the origin lies strictly inside the convex polygon, so a
    // ray cast in direction theta hits the boundary in exactly one point,
    // giving a bijection between angles theta in [0, 2*pi) and wall points.
    // A wall point is shaded exactly when its ray is blocked by some shelf,
    // so the answer is the boundary length of the wall points whose angle
    // lies in the union of the angular intervals occupied by the shelves.
    //
    // Each shelf is a segment that does not pass through the origin, so as
    // seen from the origin it spans the minor arc (less than pi) between the
    // angles of its endpoints; the sign of the cross product of the two
    // endpoint vectors tells us which of the two is the counter-clockwise
    // start of that arc. We cut every arc at angle 0 so all blocked
    // intervals live in [0, 2*pi), then sort and merge them.
    //
    // To turn a blocked angular interval into a wall length we sort the
    // polygon vertices by angle. Because the polygon is convex and the
    // origin is inside, this is just a rotation of the input order, so
    // consecutive sorted vertices stay adjacent on the boundary. Walking
    // the boundary counter-clockwise from the first sorted vertex, the
    // travelled distance s(theta) to the point hit at angle theta is a
    // monotone function, precomputed via prefix sums of edge lengths plus
    // the offset of the ray-edge intersection inside the current edge. The
    // contribution of a blocked interval [a, b] is then s(b) - s(a), with
    // intervals that straddle the anchor angle split across the wrap.

    auto norm_angle = [](coord_t a) {
        if(a < 0) {
            a += 2 * Point::PI;
        }
        return a;
    };

    vector<pair<coord_t, Point>> by_angle(n);
    for(int i = 0; i < n; i++) {
        by_angle[i] = {norm_angle(poly[i].angle()), poly[i]};
    }
    sort(by_angle.begin(), by_angle.end(), [](const auto& p, const auto& q) {
        return p.first < q.first;
    });

    vector<coord_t> bound(n + 1), pref(n + 1, 0);
    for(int i = 0; i < n; i++) {
        poly[i] = by_angle[i].second;
        bound[i] = by_angle[i].first;
        if(i > 0) {
            pref[i] = pref[i - 1] + (poly[i] - poly[i - 1]).norm();
        }
    }
    bound[n] = bound[0] + 2 * Point::PI;
    coord_t perim = pref[n - 1] + (poly[0] - poly[n - 1]).norm();

    coord_t g0 = bound[0];
    auto arc_length = [&](coord_t theta) {
        int i =
            upper_bound(bound.begin(), bound.end(), theta) - bound.begin() - 1;
        i = min(i, n - 1);
        Point dir(cos(theta), sin(theta));
        Point hit = line_line_intersection(
            Point(0, 0), dir, poly[i], poly[(i + 1) % n]
        );
        return pref[i] + (hit - poly[i]).norm();
    };

    vector<pair<coord_t, coord_t>> arcs;
    auto add_arc = [&](coord_t s, coord_t e) {
        if(s <= e) {
            arcs.emplace_back(s, e);
        } else {
            arcs.emplace_back(s, 2 * Point::PI);
            arcs.emplace_back(0, e);
        }
    };

    for(auto& [a, b]: shelves) {
        coord_t cross = a ^ b;
        if(fabs(cross) < Point::eps) {
            continue;
        }
        coord_t sa = norm_angle(a.angle()), sb = norm_angle(b.angle());
        if(cross > 0) {
            add_arc(sa, sb);
        } else {
            add_arc(sb, sa);
        }
    }

    sort(arcs.begin(), arcs.end());

    coord_t ans = 0;
    coord_t cur_lo = 0, cur_hi = -1;
    auto flush = [&]() {
        if(cur_hi < cur_lo) {
            return;
        }
        if(cur_lo < g0 - Point::eps && cur_hi > g0 + Point::eps) {
            ans += (perim - arc_length(cur_lo + 2 * Point::PI)) +
                   arc_length(cur_hi);
        } else if(cur_hi <= g0 + Point::eps) {
            ans += arc_length(cur_hi + 2 * Point::PI) -
                   arc_length(cur_lo + 2 * Point::PI);
        } else {
            ans += arc_length(cur_hi) - arc_length(cur_lo);
        }
    };

    for(auto& [s, e]: arcs) {
        if(cur_hi < cur_lo) {
            cur_lo = s;
            cur_hi = e;
        } else if(s <= cur_hi + Point::eps) {
            cur_hi = max(cur_hi, e);
        } else {
            flush();
            cur_lo = s;
            cur_hi = e;
        }
    }
    flush();

    cout << fixed << setprecision(12) << ans << '\n';
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int T = 1;
    // cin >> T;
    for(int test = 1; test <= T; test++) {
        read();
        solve();
    }

    return 0;
}
```

---

## 4. Python solution with detailed comments

```python
import sys
import math
import bisect


# Small tolerance for floating point comparisons.
EPS = 1e-12

# Pi and full circle constants.
PI = math.pi
TWO_PI = 2.0 * math.pi


def norm_angle(a):
    """
    Normalize angle into [0, 2*pi).
    atan2 returns values in [-pi, pi].
    """
    if a < 0:
        a += TWO_PI
    return a


def cross(a, b):
    """
    Cross product of vectors a and b.
    Points/vectors are represented as tuples (x, y).
    """
    return a[0] * b[1] - a[1] * b[0]


def dist(a, b):
    """
    Euclidean distance between points a and b.
    """
    return math.hypot(a[0] - b[0], a[1] - b[1])


def line_ray_edge_intersection(theta, p, q):
    """
    Intersect the ray line from origin in direction theta
    with the polygon edge line p -> q.

    Since the polygon is convex and the chosen edge is correct,
    the intersection lies on the segment p-q.
    """
    # Direction vector of the ray.
    dx = math.cos(theta)
    dy = math.sin(theta)

    # Edge direction vector.
    ex = q[0] - p[0]
    ey = q[1] - p[1]

    # We solve:
    # t * dir = p + u * edge
    #
    # Taking cross with edge:
    # cross(t * dir, edge) = cross(p, edge)
    # t = cross(p, edge) / cross(dir, edge)
    denom = dx * ey - dy * ex
    numer = p[0] * ey - p[1] * ex

    t = numer / denom

    # Intersection point.
    return (dx * t, dy * t)


def solve():
    # Read all integers from input.
    data = list(map(int, sys.stdin.buffer.read().split()))

    # Current index in the flat input list.
    idx = 0

    # Number of polygon vertices and shelves.
    n = data[idx]
    m = data[idx + 1]
    idx += 2

    # Read polygon vertices.
    poly = []
    for _ in range(n):
        x = data[idx]
        y = data[idx + 1]
        idx += 2
        poly.append((float(x), float(y)))

    # Read shelves.
    shelves = []
    for _ in range(m):
        x1 = data[idx]
        y1 = data[idx + 1]
        x2 = data[idx + 2]
        y2 = data[idx + 3]
        idx += 4
        shelves.append(((float(x1), float(y1)), (float(x2), float(y2))))

    # Sort polygon vertices by polar angle around the origin.
    # For a convex polygon containing origin, this is the boundary cyclic order.
    by_angle = []
    for p in poly:
        ang = norm_angle(math.atan2(p[1], p[0]))
        by_angle.append((ang, p))

    by_angle.sort()

    # Rebuild sorted polygon and angle array.
    poly = [p for _, p in by_angle]
    bound = [ang for ang, _ in by_angle]

    # Add cyclic closing angle.
    bound.append(bound[0] + TWO_PI)

    # Prefix lengths along polygon boundary starting from poly[0].
    pref = [0.0] * (n + 1)

    for i in range(1, n):
        pref[i] = pref[i - 1] + dist(poly[i - 1], poly[i])

    # Total perimeter.
    perimeter = pref[n - 1] + dist(poly[n - 1], poly[0])

    # Starting angle of our boundary parameterization.
    g0 = bound[0]

    def arc_length(theta):
        """
        Return boundary distance from poly[0] to the wall point hit by
        the ray at angle theta.

        theta must lie in [g0, g0 + 2*pi].
        """
        # Find rightmost bound[i] <= theta.
        i = bisect.bisect_right(bound, theta) - 1

        # Clamp to last edge.
        if i >= n:
            i = n - 1

        # Current edge is poly[i] -> poly[(i + 1) % n].
        p = poly[i]
        q = poly[(i + 1) % n]

        # Intersection of ray and current edge.
        hit = line_ray_edge_intersection(theta, p, q)

        # Boundary distance to hit point.
        return pref[i] + dist(p, hit)

    # List of blocked angular intervals in [0, 2*pi].
    arcs = []

    def add_arc(s, e):
        """
        Add CCW angular interval from s to e.
        If it wraps around 0, split it.
        """
        if s <= e:
            arcs.append((s, e))
        else:
            arcs.append((s, TWO_PI))
            arcs.append((0.0, e))

    # Convert every shelf segment to an angular interval.
    for a, b in shelves:
        c = cross(a, b)

        # Collinear with origin means zero angular measure.
        if abs(c) < EPS:
            continue

        # Endpoint angles.
        sa = norm_angle(math.atan2(a[1], a[0]))
        sb = norm_angle(math.atan2(b[1], b[0]))

        # Choose the smaller visible angular interval.
        if c > 0:
            add_arc(sa, sb)
        else:
            add_arc(sb, sa)

    # Sort intervals for merging.
    arcs.sort()

    # Answer: total shaded boundary length.
    ans = 0.0

    def interval_length(lo, hi):
        """
        Convert merged angular interval [lo, hi] in [0, 2*pi]
        to corresponding wall length.
        """
        # The interval crosses the starting angle g0.
        if lo < g0 - EPS and hi > g0 + EPS:
            return (perimeter - arc_length(lo + TWO_PI)) + arc_length(hi)

        # The whole interval lies before g0, so shift by 2*pi.
        if hi <= g0 + EPS:
            return arc_length(hi + TWO_PI) - arc_length(lo + TWO_PI)

        # The whole interval lies after g0.
        return arc_length(hi) - arc_length(lo)

    # Merge intervals and accumulate their lengths.
    cur_lo = 0.0
    cur_hi = -1.0

    for s, e in arcs:
        # No active interval.
        if cur_hi < cur_lo:
            cur_lo = s
            cur_hi = e

        # Overlap or touch.
        elif s <= cur_hi + EPS:
            if e > cur_hi:
                cur_hi = e

        # Disjoint interval.
        else:
            ans += interval_length(cur_lo, cur_hi)
            cur_lo = s
            cur_hi = e

    # Add final active interval if any.
    if cur_hi >= cur_lo:
        ans += interval_length(cur_lo, cur_hi)

    # Print with enough precision.
    print(f"{ans:.12f}")


if __name__ == "__main__":
    solve()
```

---

## 5. Compressed editorial

Each shelf blocks exactly the set of directions from the origin that intersect its segment. Thus every shelf becomes one angular interval. Use endpoint angles and the cross product to choose the smaller counter-clockwise interval; split intervals crossing `0`.

Merge all blocked angular intervals.

Now convert angular length to polygon-boundary length. Since the polygon is convex and contains the origin, every ray from the origin hits the boundary once, and polygon vertices sorted by polar angle appear in boundary order. Precompute prefix perimeter lengths in that order.

For any angle `θ`, binary search the polygon edge whose endpoint angles contain `θ`, intersect the ray with that edge, and compute the boundary distance `S(θ)` from a fixed starting vertex. Then a blocked interval `[l, r]` contributes `S(r) - S(l)`, with special handling if it wraps around the chosen starting angle.

Complexity:

```text
O((N + M) log(N + M))
```
