题意:
给定一棵有 n n n 个结点的树,再有 q q q 次询问,每次询问 u u u 到 v v v 路径上没有出现的最小编号(结点)。 ( n , q ≤ 1 0 6 ) (n,q \leq 10^6) (n,q≤106)
链接:
https://vjudge.net/problem/HDU-4916
解题思路:
如果数量级是 10^5 我将用主席树.。以
1
1
1 号结点为根,若
u
,
v
u,v
u,v 的
l
c
a
lca
lca 不为
1
1
1,则答案为
1
1
1,否则答案
u
,
v
u,v
u,v 路径可以分解成两条从根开始的路径,记分别在根往下的
b
e
l
[
u
]
bel[u]
bel[u] 和
b
e
l
[
v
]
bel[v]
bel[v] 子树内,树形
d
p
dp
dp 预处理出
f
m
n
[
u
]
fmn[u]
fmn[u],表示
u
u
u 在
b
e
l
[
u
]
bel[u]
bel[u] 子树内除了
u
u
u 到
b
e
l
[
u
]
bel[u]
bel[u] 路径上结点外的最小编号(结点),则对于单次询问,答案至少为
m
i
n
{
f
m
n
[
u
]
,
f
m
n
[
v
]
}
min\{fmn[u], fmn[v]\}
min{fmn[u],fmn[v]},此外还需考虑根结点除了
b
e
l
[
u
]
,
b
e
l
[
v
]
bel[u],bel[v]
bel[u],bel[v] 子树外的其他子树里的最小值,对应维护即可。
数据量大,请用快读。
参考代码:
#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 = 1e6 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
struct Edge{
int v, nxt;
} edge[maxn << 1];
int head[maxn], cnt;
int fmn[maxn], mn[maxn][3], pmn[maxn][3], bel[maxn];
int n, q;
void add(int u, int v){
edge[++cnt] = {v, head[u]}, head[u] = cnt;
edge[++cnt] = {u, head[v]}, head[v] = cnt;
}
void dfs1(int u, int f, int t){
bel[u] = t;
mn[u][0] = mn[u][1] = mn[u][2] = inf;
pmn[u][0] = pmn[u][1] = pmn[u][2] = 0;
for(int i = head[u]; i; i = edge[i].nxt){
int v = edge[i].v;
if(v == f) continue;
dfs1(v, u, f ? t : v);
int tmp = min(v, mn[v][0]);
if(tmp < mn[u][0]){
mn[u][2] = mn[u][1], pmn[u][2] = pmn[u][1];
mn[u][1] = mn[u][0], pmn[u][1] = pmn[u][0];
mn[u][0] = tmp, pmn[u][0] = v;
}
else if(tmp < mn[u][1]){
mn[u][2] = mn[u][1], pmn[u][2] = pmn[u][1];
mn[u][1] = tmp, pmn[u][1] = v;
}
else if(tmp < mn[u][2]){
mn[u][2] = tmp, pmn[u][2] = v;
}
}
}
void dfs2(int u, int f){
for(int i = head[u]; i; i = edge[i].nxt){
int v = edge[i].v;
if(v == f) continue;
if(v == pmn[u][0]){
fmn[v] = min(fmn[u], mn[u][1]);
}
else{
fmn[v] = min(fmn[u], mn[u][0]);
}
dfs2(v, u);
}
}
const int maxs = 1e3 + 5;
char buf[maxs], *p1 = buf, *p2 = buf;
inline char fr(){
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, maxs, stdin)) == p1 ? -1 : *p1++;
}
#define gc fr()
inline int read(int &x){
char ch; while(!isdigit(ch = gc)) if(ch == -1) return 0; x = ch ^ 48;
while(isdigit(ch = gc)) x = x * 10 + (ch ^ 48); return 1;
}
int main(){
// ios::sync_with_stdio(0); cin.tie(0);
while(read(n)){
read(q);
cnt = 0;
for(int i = 1; i <= n; ++i){
head[i] = 0;
}
for(int i = 1; i < n; ++i){
int u, v; read(u), read(v);
add(u, v);
}
dfs1(1, 0, 0);
fmn[1] = inf;
for(int i = head[1]; i; i = edge[i].nxt){
int v = edge[i].v;
fmn[v] = inf;
dfs2(v, 1);
}
int ret = 0;
while(q--){
int u, v; read(u), read(v);
u ^= ret, v ^= ret;
if(bel[u] && bel[v] && bel[u] == bel[v]) ret = 1;
else{
int tmp = inf;
if(u > v) swap(u, v);
if(v == 1) tmp = 2;
else if(u == 1){
tmp = min(fmn[v], mn[v][0]);
if(bel[v] == pmn[1][0]) tmp = min(tmp, mn[1][1]);
else tmp = min(tmp, mn[1][0]);
}
else{
tmp = min(min(fmn[u], mn[u][0]), min(fmn[v], mn[v][0]));
for(int i = 0; i < 3; ++i){
if(pmn[1][i] != bel[u] && pmn[1][i] != bel[v]){
tmp = min(tmp, mn[1][i]);
break;
}
}
}
ret = tmp;
}
printf("%d\n", ret);
}
}
return 0;
}