题解:P17553 [JAG 2026 Summer Camp #2] Edge Exchanges
观察这个题意并且手玩样例之后可以发现如果删去树
那么在
我们把
然后直接倍增找最近的与
没有无解的情况。
然后写一个很神秘的
找颜色不同的点可以转化为找路径上第一个
剩下的是如何
使用线段树二分应该可以优化到
给出
#include <bits/stdc++.h>
#define loop(i, a, b) for(int i = (a) ; i <= (int)(b) ; i++)
#define rloop(i, a, b) for(int i = (a) ; i >= (int)(b) ; i--)
#define lowbit(x) ((x) & (-(x)))
#define ls (k << 1)
#define rs (k << 1 | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 5e5 + 5;
const int INF = 5e6;
int n, m, k, tot, cnt;
int a[N], ans[N], val[N], up[N][21];
int son[N], dfn[N], top[N], dep[N], siz[N];
struct node {
int v, id;
} fa[N];
vector<node> A[N], B[N];
struct data {
ll mx, mn;
};
data empty_data = {-INF, INF};
inline data operator + (const data &x, const data &y) {
return {max(x.mx, y.mx), min(x.mn, y.mn)};
}
data tr[N << 2];
void push_up(int k) {
tr[k] = tr[ls] + tr[rs];
}
void update_point(int l, int r, int k, int p, int v) {// p is dfn
if(l == r) {
tr[k] = {v, v};
return;
}
if(p <= mid) update_point(l, mid, ls, p, v);
else update_point(mid + 1, r, rs, p, v);
push_up(k);
}
data query(int l, int r, int k, int ql, int qr) {
if(ql <= l && r <= qr) return tr[k];
data res = empty_data;
if(ql <= mid) res = res + query(l, mid, ls, ql, qr);
if(qr > mid) res = res + query(mid + 1, r, rs, ql, qr);
return res;
}
data query_path(int x, int y) {
data res = empty_data;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
res = (res + query(1, n, 1, dfn[top[x]], dfn[x]));
x = fa[top[x]].v;
}
if(dep[x] > dep[y]) swap(x, y);
res = (res + query(1, n, 1, dfn[x], dfn[y]));
return res;
}
int lca(int x, int y) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]].v;
}
if(dep[x] > dep[y]) swap(x, y);
return x;
}
void dfsB1(int u, int f) {
dep[u] = dep[f] + 1, siz[u] = 1;
up[u][0] = f;
loop(i, 1, 20) up[u][i] = up[up[u][i - 1]][i - 1];
for(auto e : B[u]) {
int v = e.v;
if(v == f) continue;
fa[v] = {u, e.id};
dfsB1(v, u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfsB2(int u, int topf) {
dfn[u] = ++tot;
update_point(1, n, 1, tot, n + 8);
top[u] = topf;
if(!son[u]) return ;
dfsB2(son[u], topf);
for(auto e : B[u]) {
int v = e.v;
if(v == fa[u].v || v == son[u]) continue;
dfsB2(v, v);
}
}
void dfsA(int u, int f) {
cnt--;
update_point(1, n, 1, dfn[u], cnt);
val[u] = cnt;
for(auto e : A[u]) {
int v = e.v;
if(v == f) continue;
dfsA(v, u);
int s = v, t = u;
int lc = lca(s, t);
rloop(i, 20, 0) {
if(up[s][i] && dep[up[s][i]] >= dep[lc] && query_path(v, up[s][i]).mx <= val[v]) s = up[s][i];
}
rloop(i, 20, 0) {
if(up[t][i] && dep[up[t][i]] >= dep[lc] && query_path(u, up[t][i]).mn > val[v]) t = up[t][i];
}
if(s != lc) ans[e.id] = fa[s].id;
else if(t != lc) ans[e.id] = fa[t].id;
else {
ans[e.id] = -1;
//loop(i, 1, n) cout << val[i] << "\n";
//cout << query_path(3, 1).mx << "\n";
}
}
}
void solve() {
cin >> n;
loop(i, 1, n - 1) {
int u, v; cin >> u >> v;
A[u].push_back({v, i}), A[v].push_back({u, i});
}
loop(i, 1, n - 1) {
int u, v; cin >> u >> v;
B[u].push_back({v, i}), B[v].push_back({u, i});
}
dfsB1(1, 0);
dfsB2(1, 1);
cnt = n + 5;
dfsA(1, 0);
loop(i, 1, n - 1) cout << ans[i] << "\n";
}
signed main() {
//freopen("trees.in", "r", stdin);
//freopen("trees.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
// int t; cin >> t; while(t--)
solve();
return 0;
}