結果
問題 |
No.3189 Semifinal Stage
|
ユーザー |
![]() |
提出日時 | 2025-06-21 01:58:18 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
RE
|
実行時間 | - |
コード長 | 6,557 bytes |
コンパイル時間 | 5,061 ms |
コンパイル使用メモリ | 296,368 KB |
実行使用メモリ | 29,924 KB |
最終ジャッジ日時 | 2025-06-21 01:58:29 |
合計ジャッジ時間 | 9,659 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | RE * 30 |
ソースコード
#include <bits/stdc++.h> using namespace std; #define ALL(x) (x).begin(),(x).end() #define REP(i, n) for(ll i=0; i<(ll)(n); i++) #define PER(i, n) for(ll i=(ll)(n)-1; i>=0; i--) template<typename T> int LB(const vector<T>& v, T x) { return lower_bound(ALL(v),x)-v.begin(); } template<typename T> int UQ(T& v) { sort(ALL(v)); v.erase(unique(ALL(v)),v.end()); return v.size(); } template<typename T> bool chmax(T &a, T b) { return a<b ? a=b, true : false; } template<typename T> bool chmin(T &a, T b) { return a>b ? a=b, true : false; } template<typename T> using rpriority_queue = priority_queue<T,vector<T>,greater<T>>; using ll=long long; const int INF=1e9+10; const ll INFL=4e18; using ld=long double; using lll=__int128_t; using ull=unsigned long long; using VI=vector<int>; using VVI=vector<VI>; using VL=vector<ll>; using VVL=vector<VL>; using PL=pair<ll,ll>; using VP=vector<PL>; using WG=vector<vector<pair<int,ll>>>; #ifdef LOCAL #include "./debug.hpp" #else #define debug(...) #define print_line #endif /// @brief LCA /// @ref verify: https://onlinejudge.u-aizu.ac.jp/status/users/Today03/submissions/1/GRL_5_C/judge/10572843/C++17 struct LCA { /// @brief コンストラクタ LCA(const vector<vector<int>>& g, int root=0) { int n=g.size(); int k=1; while((1<<k)<n) k++; par=vector<vector<int>>(k,vector<int>(n,-1)),dep=vector<int>(n); dfs(g,root,-1); for(int i=0; i<k-1; i++) for(int j=0; j<n; j++) par[i+1][j]=(par[i][j]==-1?-1:par[i][par[i][j]]); } /// @brief 頂点 u, v のLCAを返す int lca(int u, int v) { if(dep[u]<dep[v]) swap(u,v); int k=par.size(); for(int i=0; i<k; i++) if((dep[u]-dep[v])>>i&1) u=par[i][u]; if(u==v) return u; for(int i=k-1; i>=0; i--) if(par[i][u]!=par[i][v]) u=par[i][u], v=par[i][v]; return par[0][u]; } /// @brief 頂点 u, v の距離を返す int distance(int u, int v) { return dep[u]+dep[v]-2*dep[lca(u,v)]; } /// @brief 頂点 x が u-v のパス上にあるか否かを返す bool is_on_path(int u, int v, int x) { return distance(u,x)+distance(x,v)==distance(u,v); } /// @brief 頂点 u から d 回遡った位置にある頂点を返す int climb(int u, int d) { int k=par.size(); for(int i=k-1; i>=0; i--) if(d>>i&1) u=par[i][u]; return u; } vector<vector<int>> par; vector<int> dep; private: void dfs(const vector<vector<int>>& g, int now, int pre) { par[0][now]=pre; dep[now]=(pre==-1 ? 0 : dep[pre]+1); for(int nxt: g[now]) if(nxt!=pre) dfs(g,nxt,now); } }; /** * @brief 重心分解 * @param seen 探索済みフラグ * @param sz 各頂点の部分木のサイズ * * ```cpp * vector<int> sz(N); * vector<bool> seen(N); * * auto centroid_decomposition = [&](auto self, int root) -> void { * int centroid = TreeCentroid(g, root, seen, sz); * seen[centroid] = true; * * // ここに処理を書く * * for (int nxt : g[centroid]) { * if (seen[nxt]) continue; * self(self, nxt); * } * }; * centroid_decomposition(centroid_decomposition, 0); * ``` */ int TreeCentroid(const vector<vector<int>>& g, int root, vector<int>& seen, vector<int>& sz) { int n=g.size(); if(sz.empty()) sz=vector<int>(n); if(seen.empty()) seen=vector<int>(n,false); auto dfs=[&](auto dfs, int now, int pre)-> int { sz[now]=1; for(int nxt: g[now]) { if(nxt==pre||seen[nxt]) continue; sz[now]+=dfs(dfs,nxt,now); } return sz[now]; }; int total=dfs(dfs,root,-1); int centroid=root; auto dfs2=[&](auto dfs2, int now, int pre)-> void { bool ok=(total-sz[now])*2<=total; for(int nxt: g[now]) { if(nxt==pre||seen[nxt]) continue; dfs2(dfs2,nxt,now); if(sz[nxt]*2>total) ok=false; } if(ok) centroid=now; }; dfs2(dfs2,root,-1); return centroid; } /// @brief 削除可能な優先度付きキュー /// @tparam MAX trueのとき、最大値を返す template<typename T, bool MAX=true> struct ErasablePQ { priority_queue<T> pq, pq2; int siz=0; ErasablePQ()=default; /// @brief x を追加する void push(int x) { if(!MAX) x=-x; pq.push(x); siz++; } /// @brief x を削除する void erase(int x) { if(!MAX) x=-x; pq2.push(x); siz--; } /// @brief 最大値を返す T top() { while(!pq.empty()) { if(pq2.empty()) return (MAX ? pq.top() : -pq.top()); if(pq.top()==pq2.top()) { pq.pop(); pq2.pop(); } else { return (MAX ? pq.top() : -pq.top()); } } cout<<"ErasablePQ::top() : empty"<<endl; exit(1); return T(); } /// @brief 現在のサイズを返す int size() { return siz; } }; //---------------------------------------------------------- void solve() { ll N; cin>>N; VVI G(N); REP(i,N-1) { ll u,v; cin>>u>>v; u--; v--; G[u].push_back(v); G[v].push_back(u); } LCA lca(G); VI seen(N), sz(N), par(N,-1);//分解後の親 auto decomp=[&](auto&& decomp, int r, int p)->void { int c=TreeCentroid(G,r,seen,sz); seen[c]=1; par[c]=p; for(int nxt: G[c]) { if(seen[nxt]) continue; decomp(decomp,nxt,c); } }; decomp(decomp,0,-1); VI black(N); vector<ErasablePQ<int,false>> dist(N); auto change=[&](int v) { int now=v; while(now!=-1) { if(black[now]) dist[now].erase(lca.distance(now,v)); else dist[now].push(lca.distance(now,v)); now=par[now]; } black[v]^=1; }; auto say=[&](int v) { debug(v); int now=v, ans=INF; while(now!=-1) { debug(now); if(dist[now].size()) { chmin(ans,lca.distance(now,v)+dist[now].top()); debug(dist[now].top()); } now=par[now]; } cout<<ans<<'\n'; print_line; }; ll Q; cin>>Q; while(Q--) { int t, v; cin>>t>>v; v--; if(t==1) change(v); else say(v); } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); //cout<<fixed<<setprecision(15); int T=1; //cin>>T; while(T--) solve(); }