結果
| 問題 |
No.3189 Semifinal Stage
|
| コンテスト | |
| ユーザー |
Today03
|
| 提出日時 | 2025-06-21 02:16:07 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 574 ms / 4,000 ms |
| コード長 | 6,394 bytes |
| コンパイル時間 | 4,330 ms |
| コンパイル使用メモリ | 298,104 KB |
| 実行使用メモリ | 34,332 KB |
| 最終ジャッジ日時 | 2025-06-21 02:16:26 |
| 合計ジャッジ時間 | 14,723 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 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のとき、最大値を返す
/// @tparam NONE 空のときに返す値
template<typename T, bool MAX=true, T NONE=-INF>
struct ErasablePQ {
priority_queue<T> pq, pq2;
int siz=0;
ErasablePQ() { siz=0; }
/// @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());
}
}
return NONE;
}
};
//----------------------------------------------------------
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,-1>> dist(N);
auto change=[&](int v) {
int now=v;
while(now!=-1) {
if(black[v]) 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) {
if(dist[now].top()!=-1) {
chmin(ans,lca.distance(now,v)+dist[now].top());
}
now=par[now];
}
cout<<ans<<'\n';
};
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();
}
Today03