很显然的一个结论:
两条路径相交,当且仅当其中一条路径两个点的 L c a Lca Lca在另一条路径上。
离线询问路径,计算两条路径的 L c a Lca Lca,将 L c a Lca Lca的深度从大到小排序。
对于一组询问 x , y x,y x,y,我们用只要求出 x , y x,y x,y的路径上有多少个 L c a Lca Lca的个数,即当前路径能与多少路径形成相交路径。
考虑树链剖分,用树状数组维护序列 L c a Lca Lca的个数即可。
#include
using namespace std;
#define int long long
const int N = 2e5+10;
int n,m;
struct Node{
int y,Next;
}e[2*N];
int len = 0 , linkk[N];
struct Tr{
int tr[N];
#define lowbit(x) (x&(-x))
int Ask(int x){int sum = 0; for (int i = x; i; i -= lowbit(i)) sum+=tr[i];return sum;}
void Change(int x,int v){for (int i = x; i <= n; i+=lowbit(i)) tr[i]+=v;}
}tr;
struct qq{
int x,y,lca;
}q[N];
int d[N] , fa[N][30];
int num[N] , cnt = 0;
int son[N] , siz[N] , top[N];
void Insert(int x,int y){
e[++len].Next = linkk[x];
linkk[x] = len;
e[len].y = y;
}
void dfs1(int x,int dd,int faa){
int Max = 0;
d[x] = dd;
fa[x][0] = faa;
siz[x] = 1;
for (int i = linkk[x]; i; i = e[i].Next){
int y = e[i].y;
if (y == faa) continue;
dfs1(e[i].y,dd+1,x);
siz[x]+=siz[y];
if (Max < siz[y]) Max = siz[son[x] = y];
}
}
void dfs2(int x,int id){
num[x] = ++cnt; top[x] = id;
if (son[x]) dfs2(son[x] , id);
for (int i = linkk[x]; i; i = e[i].Next){
int y = e[i].y;
if (y == fa[x][0] || y == son[x]) continue;
dfs2(y,y);
}
}
void find_fa(){
for (int i = 1; i < 30; i++)
for (int j = 1; j <= n; j++)
if (fa[j][i-1] == 0) fa[j][i] = 0;
else fa[j][i] = fa[fa[j][i-1]][i-1];
}
int Lca(int x,int y){
if (d[x] < d[y]) swap(x,y);
for (int dd = d[x] - d[y] , i = 0; dd; dd>>=1 , i++)
if (dd&1) x = fa[x][i];
if (x == y) return x;
for (int i = 29; i >= 0; i--)
if (fa[x][i] != fa[y][i]) x = fa[x][i] , y = fa[y][i];
return fa[x][0];
}
bool mycmp(qq x,qq y){
return d[x.lca] > d[y.lca];
}
int Ask(int x,int y){
int ans = 0;
while (top[x] != top[y]){
if (d[top[x]] < d[top[y]]) swap(x,y);
ans+=tr.Ask(num[x]) - tr.Ask(num[top[x]] - 1);
x = fa[top[x]][0];
}
if (d[x] < d[y]) swap(x,y);
ans+=tr.Ask(num[x]) - tr.Ask(num[y]-1);
return ans;
}
signed main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%lld %lld",&n,&m);
for (int i = 1,x,y; i < n; i++)
scanf("%lld %lld",&x,&y) , Insert(x,y) , Insert(y,x);
dfs1(1,0,0);
dfs2(1,0);
find_fa();
for (int i = 1; i <= m; i++)
scanf("%lld %lld",&q[i].x,&q[i].y) , q[i].lca = Lca(q[i].x,q[i].y);
sort(q+1,q+m+1,mycmp);
int ans = 0;
for (int i = 1; i <= m; i++){
ans+=Ask(q[i].x,q[i].y);
tr.Change(num[q[i].lca],1);
}
printf("%lld",ans);
return 0;
}