#include "soccer.h"
#include <iostream>
#include <vector>
#include <array>
#include <algorithm>
#define ll long long
using namespace std;
struct LineContainer{
  struct Line{
    ll m, c;
    ll val(ll x) { return m*x+c; }
  };
  vector <Line> st;
  void push_back(Line cur) {
    while (!st.empty()) {
      if (st.back().m == cur.m) {
        if (st.back().c >= cur.c) return;
        st.pop_back();
      }
      else if (st.size() > 1) {
        auto u = st.back();
        auto v = st[st.size()-2];
        if ((u.c-v.c)*(u.m-cur.m) <= (cur.c-u.c)*(v.m-u.m)) st.pop_back();
        else break;
      }
      else break;
    }
    st.push_back(cur);
  }
  ll query(ll x) {
    if (st.empty()) return 0LL;
    else if (st.size() == 1) return st.back().val(x);
    ll l = 0, r = st.size()-2, mid;
    while (l < r) {
      mid = (l+r)/2;
      if (st[mid].val(x) >= st[mid+1].val(x)) r = mid;
      else l = mid+1;
    }
    return max(st[l].val(x), st.back().val(x));
  }
  void clear() {
    st.clear();
  }
}L;
struct LineSegTree{
  LineContainer st[8000];
  void update(ll id, ll l, ll r, ll q, LineContainer::Line cur) {
    st[id].push_back(cur);
    if (l == r) return;
    ll mid = (l+r)/2;
    if (q <= mid) update(id*2, l, mid, q, cur);
    else update(id*2+1, mid+1, r, q, cur);
  }
  ll query(ll id, ll l, ll r, ll ql, ll qr, ll x) {
    if (qr < l || r < ql) return 0LL;
    else if (ql <= l && r <= qr) return st[id].query(x);
    ll mid = (l+r)/2;
    return max(query(id*2, l, mid, ql, qr, x), query(id*2+1, mid+1, r, ql, qr, x));
  }
}LST[2000];
struct SegTree{
  ll st[8000];
  void init() {
    for (int i=0; i<8000; ++i) st[i] = -1;
  }
  void update(ll id, ll l, ll r, ll q, ll w) {
    if (l == r) {
      st[id] = w;
      return;
    }
    ll mid = (l+r)/2;
    if (q <= mid) update(id*2, l, mid, q, w);
    else update(id*2+1, mid+1, r, q, w);
    st[id] = max(st[id*2], st[id*2+1]);
  }
  ll query(ll id, ll l, ll r, ll ql, ll qr) {
    if (qr < l || r < ql) return -1;
    else if (ql <= l && r <= qr) return st[id];
    ll mid = (l+r)/2;
    return max(query(id*2, l, mid, ql, qr), query(id*2+1, mid+1, r, ql, qr));
  }
}blocks[2000], ST;
vector <array<ll, 6> > V;
ll dpR[2000][2000], dpL[2000][2000], dir[2][2][2000][2000], ans[2000][2000];
array <ll, 2> nxR[2000][2000], nxL[2000][2000];
int solve(int N, vector<vector<int>> F) {
  int f = 0;
  ST.init();
  for (int i=0; i<N; ++i) {
    array<ll, 2> p = {-1, -1};
    for (int j=0; j<N; ++j) {
      p[F[i][j]] = j;
      nxL[i][j] = p;
    }
    p = {N, N};
    for (int j=N-1; j>=0; --j) {
      p[F[i][j]] = j;
      nxR[i][j] = p;
    }
  }
  for (int i=0; i<N; ++i) {
    blocks[i].init();
    for (int j=0; j<N; ++j) {
      dpR[i][j] = dpL[i][j] = (ll)-1e18;
      if (F[i][j]) {
        ST.update(1, 0, N-1, j, i);
        continue;
      }
      dir[0][0][i][j] = ST.query(1, 0, N-1, j, nxR[i][j][1]-1)+1;
      dir[1][0][i][j] = ST.query(1, 0, N-1, nxL[i][j][1]+1, j)+1;
    }
  }
  ST.init();
  for (int i=N-1; i>=0; --i) {
    for (int j=0; j<N; ++j) {
      if (F[i][j]) {
        ST.update(1, 0, N-1, j, N-1-i);
        continue;
      }
      dir[0][1][i][j] = N-1-ST.query(1, 0, N-1, j, nxR[i][j][1]-1)-1;
      dir[1][1][i][j] = N-1-ST.query(1, 0, N-1, nxL[i][j][1]+1, j)-1;
      V.push_back({i, j, j, 0, dir[0][0][i][j], dir[0][1][i][j]});
      V.push_back({i, nxL[i][j][1]+1, j, 1, dir[1][0][i][j], dir[1][1][i][j]});
    }
  }
  sort(V.begin(), V.end(), [](auto a, auto b) {
    return (!a[3] ? nxR[a[0]][a[1]][1]-1 : a[2])-a[1] < (!b[3] ? nxR[b[0]][b[1]][1]-1 : b[2])-b[1];
  });
  for (auto [i, a, b, ty, l, r] : V) {
    auto j = (!ty ? nxR[i][a][1]-1 : b);
    ll cur = 0;
    if (l) {
      auto u = nxR[l-1][a][1];
      auto v = nxL[l-1][j][1];
      if (u < N-1 && v > 0) {
        u = nxR[l-1][u+1][0];
        v = nxL[l-1][v-1][0];
        if (u <= v) cur = max(cur, LST[l-1].query(1, 0, N-1, u, v, r-l+1));
      }
      if (!F[l-1][a]) cur = max(cur, dpR[l-1][a] - (r-l+1) * (nxR[l-1][a][1]-a));
      if (!F[l-1][j]) cur = max(cur, dpL[l-1][j] - (r-l+1) * (j-nxL[l-1][j][1]));
    }
    if (r != N-1) {
      auto u = nxR[r+1][a][1];
      auto v = nxL[r+1][j][1];
      if (u < N-1 && v > 0) {
        u = nxR[r+1][u+1][0];
        v = nxL[r+1][v-1][0];
        if (u <= v) cur = max(cur, LST[r+1].query(1, 0, N-1, u, v, r-l+1));
      }
      if (!F[r+1][a]) cur = max(cur, dpR[r+1][a] - (r-l+1) * (nxR[r+1][a][1]-a));
      if (!F[r+1][j]) cur = max(cur, dpL[r+1][j] - (r-l+1) * (j-nxL[r+1][j][1]));
    }
    if (!ty) dpR[i][b] = cur + (j-a+1) * (r-l+1), f = max(f, (int)dpR[i][b]);
    else dpL[i][b] = cur + (j-a+1) * (r-l+1);
    if (!ty && (!b || F[i][b-1])) {
      LST[i].update(1, 0, N-1, j, LineContainer::Line{-(j-a+1), dpR[i][b]});
    }
  }
  return f;
}
int biggest_stadium(int N, std::vector<std::vector<int>> F)
{
  return solve(N, F);
}
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... |