題目鏈接:點擊這裏
題意:給出一個樹,q個詢問,每次詢問給出兩個點(u,v);求和u,v距離相等的點的個數.
直接LCA求出(u,v)的距離,然後找到他們的中間點,直接從深度深的那個點網上倍增距離的一半,然後直接子樹size加加減減就好了.
#include <bits/stdc++.h>
#define Clear(x,y) memset (x,y,sizeof(x))
#define FOR(a,b,c) for (int a = b; a <= c; a++)
#define REP(a,b,c) for (int a = b; a >= c; a--)
#define fi first
#define se second
#define pii pair<int, int>
#define pli pair<long long, int>
#define pb push_back
#define mod 1000000007
using namespace std;
#define maxn 100005
#define maxm maxn<<1
struct node {
int v, next;
}edge[maxm];
int n, q, head[maxn], cnt;
int qu[maxn][2];
//LCA
int fa[maxn][22], deep[maxn];//節點i第2^j個祖先 深度
int DEG;
bool vis[maxn];
void bfs (int root) {
DEG = 20;
queue <int> q;
while (!q.empty ()) q.pop ();
deep[root] = 0;
fa[root][0] = root;
q.push (root);
memset (vis, 0, sizeof vis); vis[root] = 1;
while (!q.empty ()) {
int u = q.front (); q.pop ();
for (int i = 1; i < DEG; i++) {
fa[u][i] = fa[fa[u][i-1]][i-1];
}
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if (vis[v]) continue;
deep[v] = deep[u]+1;
fa[v][0] = u;
q.push (v);
vis[v] = 1;
}
}
}
int LCA (int u, int v) {
if (deep[u] > deep[v])
swap (u, v);
int hu = deep[u], hv = deep[v];
int tu = u, tv = v;
for (int det = hv-hu, i = 0; det; det >>= 1, i++) if (det&1) {
tv = fa[tv][i];
}
if (tu == tv)
return tu;
for (int i = DEG-1; i >= 0; i--) {
if (fa[tu][i] == fa[tv][i])
continue;
tu = fa[tu][i];
tv = fa[tv][i];
}
return fa[tu][0];
}
int num[maxn];//子樹的size
void dfs (int u, int father) {
num[u] = 1;
for (int i = head[u]; i+1; i = edge[i].next) {
int v = edge[i].v; if (v == father) continue;
dfs (v, u);
num[u] += num[v];
}
}
int find (int u, int len) {
int tmp = 0;
while ((1<<(tmp+1)) <= len) tmp++;
while (len) {
while ((1<<tmp) > len) tmp--;
u = fa[u][tmp];
len -= (1<<tmp);
}
return u;
}
void add_edge (int u, int v) {
edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;
}
int main () {
//freopen ("more.in", "r", stdin);
cin >> n;
Clear (head, -1);
cnt = 0;
for (int i = 1; i < n; i++) {
int u, v; scanf ("%d%d", &u, &v);
add_edge (u, v);
add_edge (v, u);
}
bfs (1);
dfs (1, 0);//算出每個子樹的規模
cin >> q;
for (int i = 1; i <= q; i++) {
int u, v; scanf ("%d%d", &u, &v);
if (u == v) {
printf ("%d\n", n);
continue;
}
int lca = LCA (u, v);
if (deep[u] < deep[v]) swap (u, v);
int tot = (deep[u]+deep[v]-2*deep[lca]);
if (tot&1) {
printf ("0\n");
continue;
}
int len = tot/2;
int p1 = find (u, len-1);//找到u網上走tot-1長度的祖先
int p2;
if (deep[u] == deep[v]) {
p2 = find (v, len-1);
printf ("%d\n", n-num[p1]-num[p2]);
}
else {
int mid = fa[p1][0];
printf ("%d\n", num[mid]-num[p1]);
}
}
return 0;
}