Submission #1336969

#TimeUsernameProblemLanguageResultExecution timeMemory
1336969Zero_OPObstacles for a Llama (IOI25_obstacles)C++20
100 / 100
628 ms128516 KiB
#include <bits/stdc++.h>

using namespace std;

namespace{

#define FOR(i, l, r) for(int i = (l); i < (r); ++i)
#define F0R(i, r) FOR(i, 0, r)
#define FORD(i, l, r) for(int i = (r) - 1; i >= (l); --i)
#define F0RD(i, r) FORD(i, 0, r)
#define all(v) begin(v), end(v)
#define rall(v) rbegin(v), rend(v)
#define pb push_back 
#define eb emplace_back 
#define ff first
#define ss second
#define sz(v) (int)v.size()
#define mp make_pair 
#define mt make_tuple 
#define tcT template<class T  
#define dbg(x) "[" #x " = " << (x) << "]"
tcT> bool minimize(T& a, const T& b){ return a > b ? a = b, 1 : 0; }
tcT> bool maximize(T& a, const T& b){ return a < b ? a = b, 1 : 0; }
tcT> using vc = vector<T>;
tcT> using vvc = vc<vc<T>>;
using ll = long long;
using db = double;
using pi = pair<int, int>;
using pl = pair<ll, ll>;
using vi = vc<int>;
using vl = vc<ll>;
using vpi = vc<pi>;
using vpl = vc<pl>;
using vvi = vvc<int>;
using vvl = vvc<ll>;
using vvpi = vvc<pi>;
using vvpl = vvc<pl>;

const int MAX = 2e5 + 5;

struct SparseTableMin{
  vvi st;
  SparseTableMin(vi dat) : st(){
    st.pb(dat);
    int n = sz(dat);
    for(int i = 1; (1 << i) <= n; ++i){
      st.pb(vi(n - (1 << i) + 1));
      F0R(j, n - (1 << i) + 1){
        st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
      }
    }
  }

  int query(int l, int r){
    int k = 31 - __builtin_clz(r - l + 1);
    return min(st[k][l], st[k][r - (1 << k) + 1]);
  }
};


struct SparseTableMax{
  vvi st;
  SparseTableMax(vi dat) : st(){
    st.pb(dat);
    int n = sz(dat);
    for(int i = 1; (1 << i) <= n; ++i){
      st.pb(vi(n - (1 << i) + 1));
      F0R(j, n - (1 << i) + 1){
        st[i][j] = max(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
      }
    }
  }

  int query(int l, int r){
    int k = 31 - __builtin_clz(r - l + 1);
    return max(st[k][l], st[k][r - (1 << k) + 1]);
  }
};

struct DSU{
  vi f;
  DSU() : f() {}
  DSU(int n) : f(n, -1) {}
  int root(int u){
    return f[u] < 0 ? u : (f[u] = root(f[u]));
  }
  bool join(int u, int v){
    u = root(u); v = root(v);
    if(u == v) return false;
    if(f[u] > f[v]) swap(u, v);
    f[u] += f[v];
    f[v] = u;
    return true;
  }
  bool isConnected(int a, int b){ return root(a) == root(b); }
} dsu;

namespace Tree{
  struct Edge{
    int v, wMin, wMax;
  };

  int dep[MAX], par[MAX], up[20][MAX], upMin[20][MAX], upMax[20][MAX];
  vector<Edge> adj[MAX];

  void dfsTree(int u){
    for(auto [v, wMin, wMax] : adj[u]){
      dep[v] = dep[u] + 1;
      up[0][v] = u;
      upMin[0][v] = wMin;
      upMax[0][v] = wMax;
      for(int i = 1; (1 << i) <= dep[v]; ++i){
        up[i][v] = up[i - 1][up[i - 1][v]];
        upMin[i][v] = min(upMin[i - 1][v], upMin[i - 1][up[i - 1][v]]);
        upMax[i][v] = max(upMax[i - 1][v], upMax[i - 1][up[i - 1][v]]);
      }
      dfsTree(v);
    }
  }
  
  
  void init(vector<tuple<int, int, int>> parent){
    int nodes = sz(parent);
    F0R(i, nodes){
      auto [p, wMin, wMax] = parent[i];
      par[i] = p;
      if(p != -1){
        adj[p].pb(Edge{i, wMin, wMax});
      }
    }

    F0R(i, nodes){
      if(par[i] == -1){
        dfsTree(i);
      }
    }
  }

  pi getPath(int u, int v){
    int wMin = 1e9, wMax = -1e9;
    if(dep[u] < dep[v]) swap(u, v);
    int k = dep[u] - dep[v];
    while(k > 0){
      int bit = 31 - __builtin_clz(k);
      k -= (1 << bit);
      
      minimize(wMin, upMin[bit][u]);
      maximize(wMax, upMax[bit][u]);
      u = up[bit][u];
    }

    if(u == v) return mp(wMin, wMax);
    for(int i = 31 - __builtin_clz(dep[u]); i >= 0; --i){
      if(dep[u] >= (1 << i) && up[i][u] != up[i][v]){
        minimize(wMin, upMin[i][u]);
        minimize(wMin, upMin[i][v]);
        maximize(wMax, upMax[i][u]);
        maximize(wMax, upMax[i][v]);
        u = up[i][u]; v = up[i][v];
      }
    }
    minimize(wMin, upMin[0][u]);
    minimize(wMin, upMin[0][v]);
    maximize(wMax, upMax[0][u]);
    maximize(wMax, upMax[0][v]);
    return mp(wMin, wMax);
  }
}

namespace SegTree{
#define ls (id << 1)
#define rs (id << 1 | 1)

int st[MAX << 2];
void build(int id, int l, int r, vi& A){
  if(l < r){
    int mid = l + r >> 1;
    build(ls, l, mid, A);
    build(rs, mid + 1, r, A);
    st[id] = min(st[ls], st[rs]);
  } else{
    st[id] = A[l];
  }
}

int findLeft(int id, int l, int r, int u, int v, int bound){
  if(v < l || u > r || st[id] >= bound) return -1;
  if(l == r) return l;
  int mid = l + r >> 1;
  int res = findLeft(ls, l, mid, u, v, bound);
  if(res == -1) res = findLeft(rs, mid + 1, r, u, v, bound);
  return res;
}

int findRight(int id, int l, int r, int u, int v, int bound){
  if(v < l || u > r || st[id] >= bound) return -1;
  if(l == r) return l;
  int mid = l + r >> 1;
  int res = findRight(rs, mid + 1, r, u, v, bound);
  if(res == -1) res = findRight(ls, l, mid, u, v, bound);
  return res;
}


}

int N, M, nxt[MAX], id[MAX];

void myInitialize(vector<int> A, vector<int> B){
  N = sz(A); M = sz(B);
  stack<int> st;
  F0RD(i, N){
    while(!st.empty() && A[st.top()] <= A[i]) st.pop();
    nxt[i] = (st.empty() ? N : st.top());
    st.push(i);
  }

  SegTree::build(1, 0, M - 1, B);
  vvi nxtLift(20, vi(N + 1, N));
  F0R(i, N) nxtLift[0][i] = nxt[i];
  FOR(i, 1, 20){
    F0R(j, N){
      nxtLift[i][j] = nxtLift[i - 1][nxtLift[i - 1][j]];
    }
  }

  vi par;
  vpi ed;
  int nodes = 0;
  map<tuple<int, int, int>, int> ids; //[row, l, r]
  vi row0(M);
  F0R(i, M){
    row0[i] = A[0] > B[i];
  }

  SparseTableMax maxB(B);
  auto extendLeft = [&](int i, int L){
    int l = 0, r = L - 1, newL = L;
    while(l <= r){
      int mid = l + r >> 1;
      if(A[i] > maxB.query(mid, L)) newL = mid, r = mid - 1;
      else l = mid + 1;
    }
    return newL;
  };

  auto extendRight = [&](int i, int R){
    int l = R + 1, r = M - 1, newR = R;
    while(l <= r){
      int mid = l + r >> 1;
      if(A[i] > maxB.query(R, mid)) newR = mid, l = mid + 1;
      else r = mid - 1;
    }
    return newR;    
  };  

  SparseTableMin minA(A), minB(B);
  auto reachable = [&](int lRow, int rRow, int x, int y){ //from lr -> rr using some columns in x and y
    int u = minA.query(lRow, rRow);
    int l = SegTree::findLeft(1, 0, M - 1, x, y, u);
    if(l == -1) return mp(-1, -1);
    int r = SegTree::findRight(1, 0, M - 1, x, y, u);
    return mp(l, r);
  };

  auto findFirstGreater = [&](int i, int target){
    for(int step = 17; step >= 0; --step){
      if(nxtLift[step][i] < N && A[nxtLift[step][i]] <= target) i = nxtLift[step][i];
    }
    return nxtLift[0][i];
  };

  function<int(int, int, int)> recurse = [&](int i, int l, int r){
    if(ids.count(mt(i, l, r))) return ids[mt(i, l, r)];
    ids[mt(i, l, r)] = nodes++;
    par.pb(-1);
    ed.eb(-1, -1);
    int u = nodes - 1;
    if(nxt[i] == N) return u;
    if(l == 0 && r == M - 1) return u;
    int target = min((l > 0 ? B[l - 1] : (int)1e9 + 1), (r < M - 1 ? B[r + 1] : (int)1e9 + 1));
    int upi = findFirstGreater(i, target);
    if(upi == N) return u;
    pi cand = reachable(i, upi, l, r);
    if(cand != mp(-1, -1)){
      int upl = extendLeft(upi, l), upr = extendRight(upi, r);
      par[u] = recurse(upi, upl, upr);
      ed[u] = cand;
    }
    return u;
  };

  F0R(i, M) if(row0[i] == 1){
    int j = i;
    while(i + 1 < M && row0[i + 1]) ++i;
    int u = recurse(0, j, i);
    FOR(k, j, i + 1) id[k] = u;
  }

  dsu = DSU(nodes);
  vector<tuple<int, int, int>> info(nodes, mt(-1, -1, -1));
  F0R(i, nodes) if(par[i] != -1){
    dsu.join(par[i], i);
    info[i] = mt(par[i], ed[i].ss, ed[i].ff);
  }
  Tree::init(info);
}

int myQuery(int L, int R, int S, int T){
  S = id[S];
  T = id[T];
  if(S == T) return true;
  if(!dsu.isConnected(S, T)) return false;
  auto [minW, maxW] = Tree::getPath(S, T);
  return L <= minW && minW <= maxW && maxW <= R;
}
}

void initialize(vector<int> A, vector<int> B){
  myInitialize(A, B);
}

int can_reach(int L, int R, int S, int T){
  return myQuery(L, R, S, T);
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...