結果
問題 | No.2786 RMQ on Grid Path |
ユーザー | shkiiii_ |
提出日時 | 2024-06-14 23:47:42 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 587 ms / 6,000 ms |
コード長 | 7,392 bytes |
コンパイル時間 | 3,133 ms |
コンパイル使用メモリ | 225,864 KB |
実行使用メモリ | 61,108 KB |
最終ジャッジ日時 | 2024-06-14 23:47:59 |
合計ジャッジ時間 | 16,223 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,816 KB |
testcase_01 | AC | 2 ms
6,944 KB |
testcase_02 | AC | 2 ms
6,940 KB |
testcase_03 | AC | 2 ms
6,944 KB |
testcase_04 | AC | 2 ms
6,940 KB |
testcase_05 | AC | 2 ms
6,940 KB |
testcase_06 | AC | 2 ms
6,940 KB |
testcase_07 | AC | 2 ms
6,940 KB |
testcase_08 | AC | 2 ms
6,940 KB |
testcase_09 | AC | 2 ms
6,944 KB |
testcase_10 | AC | 2 ms
6,944 KB |
testcase_11 | AC | 2 ms
6,944 KB |
testcase_12 | AC | 587 ms
54,912 KB |
testcase_13 | AC | 523 ms
54,944 KB |
testcase_14 | AC | 554 ms
55,008 KB |
testcase_15 | AC | 518 ms
54,904 KB |
testcase_16 | AC | 551 ms
55,140 KB |
testcase_17 | AC | 524 ms
55,040 KB |
testcase_18 | AC | 526 ms
55,052 KB |
testcase_19 | AC | 545 ms
55,048 KB |
testcase_20 | AC | 530 ms
55,120 KB |
testcase_21 | AC | 555 ms
55,072 KB |
testcase_22 | AC | 413 ms
55,036 KB |
testcase_23 | AC | 426 ms
55,024 KB |
testcase_24 | AC | 280 ms
57,532 KB |
testcase_25 | AC | 279 ms
57,684 KB |
testcase_26 | AC | 279 ms
57,516 KB |
testcase_27 | AC | 159 ms
13,184 KB |
testcase_28 | AC | 125 ms
6,944 KB |
testcase_29 | AC | 424 ms
52,628 KB |
testcase_30 | AC | 131 ms
7,040 KB |
testcase_31 | AC | 22 ms
5,504 KB |
testcase_32 | AC | 330 ms
52,304 KB |
testcase_33 | AC | 69 ms
5,376 KB |
testcase_34 | AC | 285 ms
61,088 KB |
testcase_35 | AC | 285 ms
61,108 KB |
testcase_36 | AC | 282 ms
61,052 KB |
ソースコード
#include<bits/stdc++.h> // #include<atcoder/all> // #include<boost/multiprecision/cpp_int.hpp> using namespace std; // using namespace atcoder; // using bint = boost::multiprecision::cpp_int; using ll = long long; using ull = unsigned long long; using P = pair<ll,ll>; using vi = vector<ll>; using vvi = vector<vi>; using vvvi = vector<vvi>; #define rep(i,n) for(ll i = 0;i < (ll)n;i++) #define ALL(x) (x).begin(),(x).end() #define sz(c) ((ll)(c).size()) #define LB(A,x) (int)(lower_bound(A.begin(),A.end(),x)-A.begin()) #define UB(A,x) (int)(upper_bound(A.begin(),A.end(),x)-A.begin()) // #define MOD 1000000007 #define MOD 998244353 template<typename T>using min_priority_queue=priority_queue<T,vector<T>,greater<T>>; template<typename T>ostream&operator<<(ostream&os,vector<T>&v){for(int i = 0;i < v.size();i++)os<<v[i]<<(i+1!=v.size()?" ":"");return os;} template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;} template<typename T1,typename T2>ostream&operator<<(ostream&os,pair<T1,T2>&p){os<<p.first<<" "<<p.second;return os;} template<typename T1,typename T2>istream&operator>>(istream&is,pair<T1,T2>&p){is>>p.first>>p.second;return is;} class UnionFind{ public: vector<int> par; UnionFind(long long size) : par(size,-1){} bool unite(int x,int y){ x = root(x),y = root(y); if(x == y)return false; if(par[y] < par[x])swap(x,y); par[x] += par[y]; par[y] = x; return true; } bool find(int x,int y){ return root(x) == root(y); } int root(int x){ return par[x] < 0 ? x : par[x] = root(par[x]); } int size(int x){ return -par[root(x)]; } }; // https://beet-aizu.github.io/library/tree/heavylightdecomposition.cpp struct HLD{ /* v := 隣接リスト id := 元々の頂点のHLD後の頂点番号。 head := heavyな辺でつながれた頂点集合の代表元。もっとも浅い頂点。 sub_sz := 部分木のサイズ par := 親 inv := HLD後の頂点番号から元々の頂点番号をかえす add_edge(a,b) := a,b間の無向辺を追加 build() := HLD 分解を実行。内部でdfs_szによる部分木の取得、dfs_hldによるHLD実行。 lca(a,b) := a,bのLCAを返す for_each(a,b,f) := 頂点a,b間の頂点(a,bを含む)にfを実行。このfにseg木などが乗る。 for_each_edge(a,b,f) := 頂点a,b間の辺にfを実行。辺はつながっている2つの頂点の内深い方と対応させる。 */ vector<vector<int>> v; vector<int> id,head,sub_sz,par,inv; HLD(int n) : v(n),id(n,-1),head(n),sub_sz(n,1),par(n,-1),inv(n){} void add_edge(int a,int b){ v[a].push_back(b); v[b].push_back(a); } void dfs_sz(int ov,int pre){ if(v[ov].size() && v[ov][0] == pre)swap(v[ov][0],v[ov].back()); par[ov] = pre; for(auto &nv : v[ov]){ if(nv == pre)continue; dfs_sz(nv,ov); sub_sz[ov] += sub_sz[nv]; if(sub_sz[nv] > sub_sz[v[ov][0]])swap(nv,v[ov][0]); } } void dfs_hld(int ov,int &pos){ id[ov] = pos++; inv[id[ov]] = ov; for(auto nv : v[ov]){ if(nv == par[ov])continue; head[nv] = (nv == v[ov][0] ? head[ov] : nv); dfs_hld(nv,pos); } } void build(int root = 0){ int pos = 0; dfs_sz(root,-1); head[root] = root; dfs_hld(root,pos); } int lca(int a,int b){ while(1){ if(id[a] > id[b])swap(a,b); if(head[a] == head[b])return a; b = par[head[b]]; } } /* 関数内でfは半開区間で値を取得するように正規化するので, BITが閉区間で実装されている場合などは auto f = [&](int a,int b){return bit.sum(a,b-1);}; の様に変更する.データ構造が半開区間で値を取得する場合は auto f = [&](int a,int b){return seg.get(a,b);}; でよい. 実装を見ればわかるが,a,bに対応する部分は hld.idで正規化されて渡されているので外部でfの宣言をするために正規化する必要はない. */ template<typename F> void for_each(int a,int b,const F& f){ while(1){ if(id[a] > id[b])swap(a,b); f(max(id[head[b]],id[a]),id[b]+1); if(head[a] != head[b])b = par[head[b]]; else break; } } template<typename F> void for_each_edge(int a,int b,const F& f){ while(1){ if(id[a] > id[b])swap(a,b); if(head[a] != head[b]){ f(id[head[b]],id[b]+1); b = par[head[b]]; }else{ if(a != b)f(id[a]+1,id[b]+1); break; } } } }; template<typename T> class Segtree{ public: using F = function<T(T,T)>; int n; F f; T ti; vector<T> dat; Segtree(){}; Segtree(F f,T ti): f(f),ti(ti){} void init(int N){ n = 1; while(n < N)n <<= 1; dat.assign(n << 1,ti); } void build(const vector<T> &v){ int N = v.size(); init(N); for(int i = 0;i < N;i++)dat[n+i] = v[i]; for(int i = n-1;i >= 0;i--)dat[i] = f(dat[(i << 1)|0],dat[(i << 1)|1]); } void set(int k,T x){ dat[k+=n] = x; while(k >>= 1){ dat[k] = f(dat[(k << 1)|0],dat[(k << 1)|1]); } } T get(int l,int r){ T vl = ti,vr = ti; for(l += n,r += n;l < r;l >>= 1,r >>= 1){ if(l & 1)vl = f(vl,dat[l++]); if(r & 1)vr = f(dat[--r],vr); } return f(vl,vr); } // max t s.t. check(query(st,t)) template<typename C> int bs(int st,C &check,T &acc,int k,int l,int r){ if(r-l <= 1){ acc = f(acc,dat[k]); return check(acc) ? k-n : -1; } int mid = (l+r) >> 1; if(mid <= st)return bs(st,check,acc,(k << 1)|1,mid,r); if(st <= l && !check(f(acc,dat[k]))){ acc = f(acc,dat[k]); return -1; } int vl = bs(st,check,acc,(k << 1)|0,l,mid); if(vl != -1)return vl; return bs(st,check,acc,(k << 1)|1,mid,r); } template<typename C> int bs(int st,C &check){ T acc = ti; return bs(st,check,acc,1,0,n); } }; int dx[] = {-1,0,0,1}; int dy[] = {0,1,-1,0}; int main(){ ios_base::sync_with_stdio(0), cin.tie(0); int h,w; cin >> h >> w; vvi a(h,vi(w)); rep(i,h)cin >> a[i]; UnionFind uf(h*w+100); vvi e(h*w+1); rep(i,h)rep(j,w){ e[a[i][j]].emplace_back(i*w+j); } vector<vector<P>> v(h*w); rep(i,h*w+1){ for(auto au : e[i]){ int oi = au/w,oj = au%w; rep(_,4){ int ni = oi + dy[_],nj = oj + dx[_]; if(ni < 0 || ni >= h || nj < 0 || nj >= w)continue; if(a[ni][nj] <= i){ if(uf.unite(au,ni*w+nj)){ v[au].emplace_back(ni*w+nj,i); } } } } } HLD hld(h*w); rep(i,h*w){ for(auto au : v[i]){ hld.add_edge(au.first,i); } } hld.build(); auto f = [](ll a,ll b){return max(a,b);}; Segtree<ll> seg(f,-1); { vi init(h*w,-1); rep(i,h*w){ for(auto au : v[i]){ if(hld.par[i] == au.first){ init[hld.id[i]] = au.second; }else{ init[hld.id[au.first]] = au.second; } } } // cout << init << " a\n"; seg.build(init); } int Q;cin >> Q; while(Q--){ int rs,cs,rt,ct;cin >> rs >> cs >> rt >> ct; rs--;cs--;rt--;ct--; rs = rs*w+cs;rt = rt*w+ct; ll res = 0; auto g = [&](int l,int r){ res = max(res,seg.get(l,r)); }; hld.for_each_edge(rs,rt,g); cout << res << "\n"; } /* rep(i,h*w){ for(auto au : v[i]){ cout << i << " " << au << "\n"; } } */ return 0; }