Submission #1264116

#TimeUsernameProblemLanguageResultExecution timeMemory
1264116aihoiLong Mansion (JOI17_long_mansion)C++20
0 / 100
205 ms20096 KiB
#include <bits/stdc++.h> using namespace std; using pii = pair<int,int>; using ll = long long; // Cách 2: segment tree + memo trên các đoạn [l,r] // Input giống code gốc. Không giả sử K <= 20. struct SegMin { int n; vector<int> st; void build(const vector<int>& a) { n = (int)a.size() - 1; // a is 1..n-1 st.assign(4*(n+5), INT_MAX); build_rec(1,1,n,a); } void build_rec(int p,int l,int r,const vector<int>& a){ if(l==r){ st[p]=a[l]; return; } int m=(l+r)/2; build_rec(p<<1,l,m,a); build_rec(p<<1|1,m+1,r,a); st[p]=min(st[p<<1], st[p<<1|1]); } // find first index in [ql,qr] with value < threshold. return -1 if none. int find_first_less(int ql,int qr,int threshold){ if(ql>qr || n==0) return -1; return find_rec(1,1,n,ql,qr,threshold); } int find_rec(int p,int l,int r,int ql,int qr,int thresh){ if(ql>r || qr<l) return -1; if(st[p] >= thresh) return -1; if(l==r) return l; int m=(l+r)/2; int res = find_rec(p<<1,l,m,ql,qr,thresh); if(res!=-1) return res; return find_rec(p<<1|1,m+1,r,ql,qr,thresh); } }; struct SegMax { int n; vector<int> st; void build(const vector<int>& a) { n = (int)a.size() - 1; // a is 1..n-1 st.assign(4*(n+5), INT_MIN); build_rec(1,1,n,a); } void build_rec(int p,int l,int r,const vector<int>& a){ if(l==r){ st[p]=a[l]; return; } int m=(l+r)/2; build_rec(p<<1,l,m,a); build_rec(p<<1|1,m+1,r,a); st[p]=max(st[p<<1], st[p<<1|1]); } // find last index in [ql,qr] with value > threshold. return -1 if none. int find_last_greater(int ql,int qr,int threshold){ if(ql>qr || n==0) return -1; return find_rec(1,1,n,ql,qr,threshold); } int find_rec(int p,int l,int r,int ql,int qr,int thresh){ if(ql>r || qr<l) return -1; if(st[p] <= thresh) return -1; if(l==r) return l; int m=(l+r)/2; // search right child first to get last index int res = find_rec(p<<1|1,m+1,r,ql,qr,thresh); if(res!=-1) return res; return find_rec(p<<1,l,m,ql,qr,thresh); } }; int n, q; vector<int> req; // 1..n-1 vector<vector<int>> rooms; // 1..n // memo map: key = (ll)l<<32 | r -> value pair(finalL, finalR) unordered_map<unsigned long long, pair<int,int>> mp; SegMin segMin; SegMax segMax; inline unsigned long long key_lr(int l,int r){ return ( (unsigned long long)l << 32 ) | (unsigned long long)r; } pair<int,int> expand_interval(int l,int r){ unsigned long long k0 = key_lr(l,r); if(mp.find(k0)!=mp.end()) return mp[k0]; vector<unsigned long long> visited; int curL = l, curR = r; while(true){ unsigned long long curk = key_lr(curL, curR); if(mp.find(curk)!=mp.end()){ // found cached result for this exact state auto res = mp[curk]; for(auto vk: visited) mp[vk] = res; return res; } visited.push_back(curk); // try expand right: find first corridor i >= curR with last_pos[i] < curL int start = curR; // corridor indices start..n-1 int i = -1; if(start <= n-1) i = segMin.find_first_less(start, n-1, curL); int newR = (i == -1 ? n : i); if(newR > curR){ curR = newR; continue; // try again } // try expand left: find last corridor i <= curL-1 with first_pos[i] > curR int end = curL - 1; int j = -1; if(end >= 1) j = segMax.find_last_greater(1, end, curR); int newL = (j == -1 ? 1 : j+1); if(newL < curL){ curL = newL; continue; } // neither side expanded break; } pair<int,int> ans = {curL, curR}; for(auto vk: visited) mp[vk] = ans; return ans; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); if(!(cin >> n)) return 0; req.assign(n+1, 0); for(int i=1;i<=n-1;i++) cin >> req[i]; rooms.assign(n+1, {}); int totalKeys = 0; for(int i=1;i<=n;i++){ int b; cin >> b; totalKeys += b; rooms[i].resize(b); for(int j=0;j<b;j++) cin >> rooms[i][j]; } // Coordinate compress key ids (because key ids can be large) vector<int> allkeys; allkeys.reserve(totalKeys + n); for(int i=1;i<=n;i++) for(int x: rooms[i]) allkeys.push_back(x); for(int i=1;i<=n-1;i++) allkeys.push_back(req[i]); sort(allkeys.begin(), allkeys.end()); allkeys.erase(unique(allkeys.begin(), allkeys.end()), allkeys.end()); auto getid = [&](int x){ return (int)(lower_bound(allkeys.begin(), allkeys.end(), x) - allkeys.begin()); }; // remap for(int i=1;i<=n;i++) for(auto &x: rooms[i]) x = getid(x); for(int i=1;i<=n-1;i++) req[i] = getid(req[i]); int K = (int)allkeys.size(); // compute last_pos[i] = last occurrence position <= i of key req[i] vector<int> lastOcc(K, 0); vector<int> last_pos(n+1, 0); // 1..n-1 for(int p=1;p<=n;p++){ for(int x: rooms[p]) lastOcc[x] = p; if(p <= n-1) last_pos[p] = lastOcc[ req[p] ]; } // compute first_pos[i] = first occurrence position >= i+1 of key req[i] vector<int> nextOcc(K, n+1); vector<int> first_pos(n+1, n+1); for(int p=n;p>=1;p--){ for(int x: rooms[p]) nextOcc[x] = p; if(p <= n-1) first_pos[p] = nextOcc[ req[p] ]; } // build segment trees on corridors 1..n-1 if(n-1 >= 1){ // last_pos: if no occurrence -> 0. first_pos: if none -> n+1 segMin.build(last_pos); segMax.build(first_pos); } else { // handle trivial small n: our code expects seg trees to be valid // leave them empty (they handle n==0 case) } cin >> q; while(q--){ int l,r; cin >> l >> r; if(l <= r){ auto res = expand_interval(l,l); if(res.second >= r) cout << "YES\n"; else cout << "NO\n"; } else { auto res = expand_interval(l,l); if(res.first <= r) cout << "YES\n"; else cout << "NO\n"; } } return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...