제출 #819312

#제출 시각아이디문제언어결과실행 시간메모리
819312senthetaTourism (JOI23_tourism)C++17
100 / 100
2724 ms33400 KiB
// author : sentheta aka vanwij #ifdef VANWIJ #include"/home/user/code/bits/stdc++.h" #define DBG 1 #else #include"bits/stdc++.h" #define DBG 0 #endif using namespace std; #define Int long long #define V vector #define pii pair<int,int> #define ff first #define ss second static mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count()); #define pow2(x) (1LL<<(x)) #define msb(x) (63-__builtin_clzll(x)) #define bitcnt(x) (__builtin_popcountll(x)) #define nl '\n' #define _ << ' ' << #define all(x) (x).begin(), (x).end() #define rep(i,a,b) for(int i = (int)(a); i < (int)(b); i++) #define cerr if(DBG) cout #define dbg(x) {cerr << "?" << #x << " : " << (x) << endl << flush;} // #define int long long // const Int MOD = 1e9+7; const Int MOD = 998244353; Int bpow(Int a,Int b){ Int ret = 1; for(;b; a=a*a%MOD,b/=2) if(b&1) ret = ret*a%MOD; return ret; } Int inv(Int a){return bpow(a,MOD-2);} void solve(); int TC, ALLTC; signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cout << fixed << setprecision(7); // cin >> ALLTC; for(TC=1; TC<=ALLTC; TC++) solve(); return 0; solve(); } const int N = 1e5+69; const int LN = 18; const int SN = 600; int hilbert(int x, int y){ int d = 0; for(int s=1LL<<(LN-1); s; s>>=1){ bool rx=x&s, ry=y&s; d = d<<2 | rx*3^ry; if(!ry){ if(rx){ x = (1<<LN)-x; y = (1<<LN)-y; } swap(x,y); } } return d; } int n, m, q; int a[N]; // tree utilities V<int> adj[N]; int d[N], p[N]; int getMinDepth(int x,int y){ return d[x]<d[y] ? x : y; } int getMaxDepth(int x,int y){ return d[x]>d[y] ? x : y; } struct Stable{ int v[2*N][LN]; void build(){ rep(lg,1,LN) for(int i=0; i+(1<<lg)-1<2*N; i++) v[i][lg] = getMinDepth(v[i][lg-1], v[i+(1<<(lg-1))][lg-1]); } int qry(int l,int r){ int lg = __lg(r-l+1); return getMinDepth(v[l][lg], v[r-(1<<lg)+1][lg]); } } stable; int t[N], tim; int getLca(int x,int y){ if(!(t[x]<t[y])) swap(x,y); return stable.qry(t[x],t[y]); } void dfs_init(int x=1){ t[x] = tim; stable.v[tim++][0] = x; for(int y : adj[x]) if(y!=p[x]){ d[y] = d[x]+1; p[y] = x; dfs_init(y); stable.v[tim++][0] = x; } } // s = {t[nodes]} // multiset<int> s; #define ull unsigned long long // van Emde Boas tree. Maintains a set of integers in range [0, 2^B) and supports operations // findNext(i): returns minimum j >= i in set, or 2^B if none exist // findPrev(i): returns maximum j <= i in set, or -1 if none exist // insert(i), erase(i): insert/erase i into the set // empty(): returns TRUE if the set is empty // clear(): empties the set // init(bts): inits the set, after the call i will be in the set if bts[i] = 1. bts should be a bitset, but can be a vector of 0/1 // All operations except empty, clear and init are O(log B) = O(log log 2^B) with good constants template<int B, typename ENABLE = void> class VEBTree { private: const static int K = B / 2, R = (B + 1) / 2, M = (1 << B); const static int S = 1 << K, MASK = (1 << R) - 1; array<VEBTree<R>, S> ch; VEBTree<K> act; int mi, ma; public: bool empty() const { return ma < mi; } int findNext(int i) const { if (i <= mi) return mi; if (i > ma) return M; int j = i >> R, x = i & MASK; int res = ch[j].findNext(x); if (res <= MASK) return (j << R) + res; j = act.findNext(j + 1); return (j >= S) ? ma : ((j << R) + ch[j].findNext(0)); } int findPrev(int i) const { if (i >= ma) return ma; if (i < mi) return -1; int j = i >> R, x = i & MASK; int res = ch[j].findPrev(x); if (res >= 0) return (j << R) + res; j = act.findPrev(j - 1); return (j < 0) ? mi : ((j << R) + ch[j].findPrev(MASK)); } void insert(int i) { if (i <= mi) { if (i == mi) return; swap(mi, i); if (i == M) ma = mi; // we were empty if (i >= ma) return; // we had mi == ma } else if (i >= ma) { if (i == ma) return; swap(ma, i); if (i <= mi) return; // we had mi == ma } int j = i >> R; if (ch[j].empty()) act.insert(j); ch[j].insert(i & MASK); } void erase(int i) { if (i <= mi) { if (i < mi) return; i = mi = findNext(mi + 1); if (i >= ma) { if (i > ma) ma = -1; // we had mi == ma return; // after erase we have mi == ma } } else if (i >= ma) { if (i > ma) return; i = ma = findPrev(ma - 1); if (i <= mi) return; // after erase we have mi == ma } int j = i >> R; ch[j].erase(i & MASK); if (ch[j].empty()) act.erase(j); } void clear() { mi = M, ma = -1; act.clear(); for (int i = 0; i < S; ++i) ch[i].clear(); } template<class T> void init(const T& bts, int shift = 0, int s0 = 0, int s1 = 0) { s0 = -shift + bts.findNext(shift + s0, shift + M-1 - s1); s1 = M-1 - (-shift + bts.findPrev(shift + M-1-s1, shift + s0)); if (s0 + s1 >= M) clear(); else { act.clear(); mi = s0, ma = M-1 - s1; ++s0; ++s1; for (int j = 0; j < S; ++j) { ch[j].init(bts, shift + (j << R), max(0, s0 - (j << R)), max(0, s1 - ((S-1-j) << R))); if (! ch[j].empty()) act.insert(j); } } } }; template<int B> class VEBTree<B, enable_if_t<(B <= 6)>> { private: const static int M = (1 << B); ull act; public: bool empty() const { return !act; } void clear() { act = 0; } int findNext(int i) const { return ((i < M) && (act >> i)) ? i + __builtin_ctzll(act >> i) : M; } int findPrev(int i) const { return ((i != -1) && (act << (63 - i))) ? i - __builtin_clzll(act << (63 - i)) : -1; } void insert(int i) { act |= 1ull << i; } void erase(int i) { act &= ~(1ull << i); } template<class T> void init(const T& bts, int shift = 0, int s0 = 0, int s1 = 0) { if (s0 + s1 >= M) act = 0; else act = bts.getRange(shift + s0, shift + M-1-s1) << s0; } }; #undef ull VEBTree<LN> s; int cnt[2*N]; int pathlen = 0; int getSemipath(int i,int j){ return d[stable.v[j][0]] - d[stable.qry(i,j)]; // assert(i <= j); // int u = stable.v[i][0]; // int v = stable.v[j][0]; // return d[v] - d[getLca(u,v)]; } void insert(int i){ cnt[i]++; // assert(cnt[i]>=0); if(cnt[i] > 1) return; int prvi = s.findPrev(i); int nxti = s.findNext(i); s.insert(i); // remove prv-nxt if(prvi!=-1 && nxti!=(1<<LN)){ pathlen -= getSemipath(prvi, nxti); } // connect prv-i if(prvi!=-1){ pathlen += getSemipath(prvi, i); } // connect i-nxt if(nxti!=(1<<LN)){ pathlen += getSemipath(i, nxti); } } void erase(int i){ cnt[i]--; // assert(cnt[i]>=0); if(cnt[i] >= 1) return; s.erase(i); int prvi = s.findPrev(i); int nxti = s.findNext(i); // remove prv-i if(prvi!=-1){ pathlen -= getSemipath(prvi, i); } // remove i-nxt if(nxti!=(1<<LN)){ pathlen -= getSemipath(i, nxti); } // connect prv-nxt if(prvi!=-1 && nxti!=(1<<LN)){ pathlen += getSemipath(prvi, nxti); } } int ql[N], qr[N], qans[N]; int qhsh[N]; void solve(){ cin >> n >> m >> q; rep(i,0,n-1){ int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } dfs_init(); stable.build(); // rep(i,1,n+1) cerr << t[i] << " "; // cerr << nl; rep(i,1,m+1){ cin >> a[i]; } V<int> ord; rep(i,1,q+1){ cin >> ql[i] >> qr[i]; ord.push_back(i); // qhsh[i] = hilbert(ql[i], qr[i]); } sort(all(ord),[&](int i,int j){ // return qhsh[i] < qhsh[j]; if(ql[i]/SN==ql[j]/SN) return qr[i] < qr[j]; return ql[i]/SN < ql[j]/SN; }); int l=1, r=1; s.clear(); insert(t[a[1]]); for(int i : ord){ while(ql[i] < l) insert(t[a[--l]]); while(r < qr[i]) insert(t[a[++r]]); while(l < ql[i]) erase(t[a[l++]]); while(qr[i] < r) erase(t[a[r--]]); // assert(l==ql[i] && r==qr[i]); // leftmost and rightmost node int li = s.findNext(0); int ri = s.findPrev((1<<LN)-1); int u = stable.v[li][0]; int v = stable.v[ri][0]; int lca = getLca(u,v); // dbg(pathlen); int ans = pathlen + d[u]-d[lca]; // int ans = pathlen + d[stable.v[li][0]]-d[stable.qry(li,ri)]; qans[i] = ans; } rep(i,1,q+1){ cout << qans[i]+1 << nl; } }

컴파일 시 표준 에러 (stderr) 메시지

tourism.cpp: In function 'int hilbert(int, int)':
tourism.cpp:68:18: warning: suggest parentheses around arithmetic in operand of '|' [-Wparentheses]
   68 |   d = d<<2 | rx*3^ry;
      |              ~~~~^~~
#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...