题意:
给定一棵有 n n n 个结点的树,再有 q q q 次询问,每次询问以 X X X 为根时, Y Y Y 的子结点中、后代结点中编号最小的结点各是哪个,若 Y Y Y 是叶结点,输出无解。 ( n , q ≤ 1 0 5 ) (n,q \leq 10^5) (n,q≤105)
链接:
https://vjudge.net/problem/HDU-4008
解题思路:
如果仅要求以 1 1 1 为根,则树形 d p dp dp 一下就可以得到答案。考虑换根,共两种情况,①: X X X 是 Y Y Y 的祖先,则 Y Y Y 会多一棵往父结点方向的子树;②:否则直接查询,答案不变。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
vector<pii> qr[maxn];
vector<int> G[maxn];
int vis[maxn], mn[maxn][2], mn2[maxn][2], fmn[maxn][2], pmn[maxn][2];
pii ans[maxn];
int n, q;
void dfs1(int u, int f){
mn[u][0] = mn[u][1] = inf;
mn2[u][0] = mn2[u][1] = inf;
pmn[u][0] = pmn[u][1] = 0;
for(auto &v : G[u]){
if(v == f) continue;
dfs1(v, u);
if(v < mn[u][0]){
mn2[u][0] = mn[u][0];
mn[u][0] = v, pmn[u][0] = v;
}
else if(v < mn2[u][0]){
mn2[u][0] = v;
}
int w = min(v, mn[v][1]);
if(w < mn[u][1]){
mn2[u][1] = mn[u][1];
mn[u][1] = w, pmn[u][1] = v;
}
else if(w < mn2[u][1]){
mn2[u][1] = w;
}
}
}
void dfs2(int u, int f){
vis[u] = 1;
for(auto &it : qr[u]){
int v = it.second, p = it.first;
if(vis[v]){
if(vis[pmn[v][0]]){
ans[p].first = min(fmn[v][0], mn2[v][0]);
}
else{
ans[p].first = min(fmn[v][0], mn[v][0]);
}
if(vis[pmn[v][1]]){
ans[p].second = min(fmn[v][1], mn2[v][1]);
}
else{
ans[p].second = min(fmn[v][1], mn[v][1]);
}
}
else{
ans[p] = {mn[v][0], mn[v][1]};
}
}
for(auto &v : G[u]){
if(v == f) continue;
fmn[v][0] = u;
if(v == pmn[u][1]){
fmn[v][1] = min(min(u, fmn[u][1]), mn2[u][1]);
}
else{
fmn[v][1] = min(min(u, fmn[u][1]), mn[u][1]);
}
dfs2(v, u);
}
vis[u] = 0;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int t; cin >> t;
while(t--){
cin >> n >> q;
for(int i = 1; i <= n; ++i){
G[i].clear();
qr[i].clear();
}
for(int i = 1; i < n; ++i){
int u, v; cin >> u >> v;
G[u].pb(v), G[v].pb(u);
}
for(int i = 1; i <= q; ++i){
int x, y; cin >> x >> y;
qr[x].pb({i, y});
}
dfs1(1, 0);
fmn[1][0] = fmn[1][1] = inf;
dfs2(1, 0);
// for(int i = 1; i <= n; ++i){
// cout << i << " : " << mn[i][0] << " " << mn2[i][0] << " "<< fmn[i][0] << " | "
// << mn[i][1] << " " << mn2[i][1] << " " << fmn[i][1] << endl;
// }
for(int i = 1; i <= q; ++i){
if(ans[i].first == inf) cout << "no answers!\n";
else cout << ans[i].first << " " << ans[i].second << "\n";
}
cout << "\n";
}
return 0;
}