1. Abridged Problem Statement  
Given n houses and n offices located at integer stations on a circular railway of length L (stations numbered 1…L, distance between adjacent stations is 1), match each house to a unique office so as to minimize the total of shortest-circle distances traveled by all employees. Output the minimal total travel time and for each house (in input order) the 1-based index of its assigned office.  

2. Detailed Editorial  

Overview  
We want a minimum‐cost perfect matching between two equal-size point sets on a circle, cost = circular distance. A classical trick is to “cut” the circle at some point, turn it into a line of length L, and match greedily by sorting—but the best cut must be chosen. One can show the cost as a function of cut position along the circle is piecewise linear, and its minima occur when the cut passes a point. We can evaluate the total cost for one cut in O(n) and then update it for all 2n event‐positions in O(n log n) by sorting events by the change in the cumulative balance of (houses minus offices). Finally, we reconstruct the matching by a simple stack sweep around the chosen cut.

Detailed Steps  

1. Model Points and Types  
   - Create 2n “points”: each house contributes (position, index, +1), each office (position, index, –1).  
   - +1 means “one more house waiting,” –1 means “one more office waiting.”  

2. Sort on the Circle  
   - Sort points by position x; tie-break by type (offices before houses) and by index.  
   - Duplicate the first point with x+L to close the circle, so we have a circular list of length 2n.  

3. Compute Gaps and Balances  
   - For i=0…2n–1, define  
       gap[i] = x[i+1]–x[i],  
       balance[i] = sum of types for j=0…i (net waiting houses).  
   - The full circle length = sum of gap[i] = L.  

4. Initial Cost at Cut=point[0]  
   - If we cut just to the left of point[0], then each gap[i] is crossed by exactly balance[i] employees.  
   - Initial cost = Σ gap[i] * balance[i].  

5. Sweep Cuts Efficiently  
   - As we move the cut forward along the circle, when the cut crosses gap[i], all those balance[i] employees flip from going “across that gap” to not going, changing total cost.  
   - One can show that ordering the 2n events by balance[i] allows us to update the cost in O(1) per event:  
       When balance increases by Δ, cost += len · Δ – (L–len) · Δ,  
       where len = total length of gaps already crossed by the moving cut.  
   - Track the minimum cost and record which gap index achieves it.  

6. Reconstruct Matching  
   - Starting just after the optimal cut index, sweep along the sorted points in circle order.  
   - Maintain a stack; for each point:  
       • If stack is empty or top.type == point.type, push(point).  
       • Else pop() gives a partner of opposite type; if point is a house (type=+1), match it with office=top; else match top.house with point.office.  
   - This greedy stack‐pairing works because on a line the sorted order of endpoints yields the minimum total distance matching.  

Complexities  
- Sorting 2n points: O(n log n).  
- Computing gaps, balances: O(n).  
- Sorting events by balance: O(n log n).  
- Sweep to find best cut: O(n).  
- Reconstruction: O(n).  
Overall O(n log n), suitable for n up to 50 000.  
3. C++ Solution
```cpp
#include <bits/stdc++.h>

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;
};

int n, L;
vector<int> a, b;

void read() {
    cin >> n >> L;
    a.resize(n);
    b.resize(n);
    cin >> a >> b;
}

struct Point {
    int x, i, type;
    Point(int x, int i, int type) : x(x), i(i), type(type) {}

    bool operator<(const Point& other) const {
        if(x != other.x) {
            return x < other.x;
        }
        if(type != other.type) {
            return type < other.type;
        }

        return i < other.i;
    }
};

void solve() {
    // Put all 2n locations on the circle as events: a house is a +1 event, an
    // office a -1 event. If we cut the circle open at some position and walk it
    // linearly, the optimal matching pairs houses and offices like balanced
    // brackets, and the cost contributed by the gap after event i equals
    // |prefix balance at i| times the gap length. For a fixed cut the cost is
    // sum of gap[i] * balance[i] (with the chosen cut making all the relevant
    // balances effectively non-negative).
    //
    // We start from the cut before the first sorted event (cost = sum gap[i] *
    // balance[i]) and then rotate the cut to every event in increasing order of
    // balance. Rotating past an event with balance v shifts which side of the
    // circle each gap is counted on; processing events by ascending balance and
    // incrementally updating candidate lets us evaluate every rotation in O(n)
    // total and keep the minimum.
    //
    // Once the best cut ans_i is known, we replay the circle from just after it
    // and match events with a stack (houses against offices like brackets) to
    // recover, for each employee, the 1-based office index.

    vector<Point> points;
    for(int i = 0; i < n; i++) {
        points.emplace_back(a[i], i, 1);
        points.emplace_back(b[i], i, -1);
    }

    sort(points.begin(), points.end());
    points.emplace_back(points[0].x + L, points[0].i, points[0].type);

    int64_t candidate = 0;
    int bal = 0;

    vector<int64_t> gaps;
    vector<int> balances;
    for(int i = 0; i < 2 * n; i++) {
        bal += points[i].type;
        balances.push_back(bal);

        int64_t gap = points[i + 1].x - points[i].x;
        gaps.push_back(gap);

        candidate += gap * bal;
    }

    vector<int> match(2 * n);
    iota(match.begin(), match.end(), 0);
    sort(match.begin(), match.end(), [&](int i, int j) {
        return balances[i] < balances[j];
    });

    int64_t best = numeric_limits<int64_t>::max(), len = 0, last = 0;
    int ans_i = 0;
    for(int i = 0; i < 2 * n; i++) {
        int j = match[i];
        candidate += len * (balances[j] - last);
        candidate -= (L - len) * (balances[j] - last);
        if(candidate < best) {
            best = candidate;
            ans_i = j;
        }
        last = balances[j];
        len += gaps[j];
    }

    cout << best << '\n';

    vector<int> ans(n);
    stack<Point> st;
    for(int pos = (ans_i + 1) % (2 * n), i = 0; i < 2 * n;
        i++, pos = (pos + 1) % (2 * n)) {
        if(st.empty() || st.top().type == points[pos].type) {
            st.push(points[pos]);
        } else {
            if(points[pos].type == 1) {
                ans[points[pos].i] = st.top().i + 1;
            } else {
                ans[st.top().i] = points[pos].i + 1;
            }
            st.pop();
        }
    }
    cout << 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();
        // cout << "Case #" << test << ": ";
        solve();
    }

    return 0;
}
```

4. Python Solution with Detailed Comments  
```python
import sys
def solve():
    data = sys.stdin.read().split()
    it = iter(data)
    n = int(next(it))
    L = int(next(it))
    A = [int(next(it)) for _ in range(n)]
    B = [int(next(it)) for _ in range(n)]

    # Build 2n points: (position, index, type)
    # type = +1 for house, -1 for office.
    pts = []
    for i, x in enumerate(A):
        pts.append((x, i, +1))
    for i, x in enumerate(B):
        pts.append((x, i, -1))

    # Sort by position, then type, then index
    pts.sort(key=lambda p: (p[0], p[2], p[1]))
    # Close the circle by repeating the first point at +L
    pts.append((pts[0][0] + L, pts[0][1], pts[0][2]))

    # Compute gap[i] and balance[i], and the initial cost
    gap = [0]*(2*n)
    bal = [0]*(2*n)
    total_len = 0
    cur_bal = 0
    cost = 0
    for i in range(2*n):
        cur_bal += pts[i][2]
        bal[i] = cur_bal
        gap[i] = pts[i+1][0] - pts[i][0]
        total_len += gap[i]
        cost += gap[i] * cur_bal

    # Prepare events sorted by balance
    order = list(range(2*n))
    order.sort(key=lambda i: bal[i])

    best_cost = cost
    best_idx = 0
    prefix_len = 0
    last_bal = 0

    # Sweep the cut along the circle across each gap in balance order
    for idx in order:
        d = bal[idx] - last_bal
        # Update cost for crossing this gap
        cost += prefix_len * d - (total_len - prefix_len) * d
        if cost < best_cost:
            best_cost = cost
            best_idx = idx
        prefix_len += gap[idx]
        last_bal = bal[idx]

    # Output minimal cost
    out = [str(best_cost)]

    # Reconstruct the matching
    ans = [-1]*n
    st = []
    pos = (best_idx + 1) % (2*n)
    for _ in range(2*n):
        x, i, t = pts[pos]
        if not st or st[-1][2] == t:
            # push unmatched endpoint
            st.append((x, i, t))
        else:
            # pop and match
            x2, j, t2 = st.pop()
            if t == +1:
                # current is house, popped was office
                ans[i] = j+1
            else:
                # popped was house, current is office
                ans[j] = i+1
        pos = (pos + 1) % (2*n)

    # Append matching
    out.append(" ".join(map(str, ans)))
    print("\n".join(out))

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

5. Compressed Editorial  
- Represent each house as +1, each office as –1 on the circle.  
- Sort 2n endpoints; close the loop by appending the first at +L.  
- Compute gaps and prefix balances; initial cost = Σ gap[i]*balance[i].  
- Events: crossing gap[i] at balance[i] changes cost by prefix_len*Δ – (L–prefix_len)*Δ.  
- Sort events by balance and sweep to find minimal cost & cut position.  
- Reconstruct matching with a stack in O(n) by pairing opposite endpoints in order.