给出一棵树,询问m条路径,有多少对路径相交于一点。
路径相交只有两种情况,一种是相同lca,一种是不同lca。
先对路径[a,b]预处理,记录lca(a,b)下a,b分别在哪个儿子。
对于相同lca的:
当前查询路径[a,b],则和该路径只在lca相交的路径数等于该lca(a,b)的路径总个数-在a下儿子的个数-在b下儿子的个数+ab下儿子的个数(容斥)。
这里注意的是,如果先统计所有儿子的个数,那么对于单点的路径,他会自己和自己匹配,最后需要减掉。最后结果就是总和/2.
如果是边处理边统计,则不会出现自己和自己匹配,最后结果也不需要除2.
对于不同lca的,那么相交必定是一条路径经过另外一条路径的lca。那么对于一个路径[a,b],那么就是统计其他路径的lca在lca(a,b)之上,而且其中一个端点在lca(a,b)的子树中且不在a,b的子树中。
因此由于需要统计比lca(a,b)小的路径,这里就有了偏序。对lca根据深度排序。对于lca(a,b),深度比它小的路径已经处理完了。那么和就是在lca(a,b)的子树的节点-在a子树的节点-在b子树的节点。
统计个数可以直接用树状数组。统计子树可以利用dfs序的进和出。求a子树的个数就是sum(out[a]) - sum(in[a]-1) (包括a自己)。
vector<int> g[N];
int dep[N],fa[N][20],dfn[N],in[N],out[N];
int la[N];
int a[N],b[N],pa[N],pb[N];
int idx;
void dfs(int t, int f){
dep[t] = dep[f]+1;
in[t] = idx;
dfn[idx++]=t;
fa[t][0] = f;
for(int i = 1; i <20; ++i){
fa[t][i] = fa[fa[t][i-1]][i-1];
}
for(int u : g[t]){
if(u==f)continue;
dfs(u,t);
}
out[t] = idx-1;
}
int lca(int a, int b){
if(dep[a]<dep[b])swap(a,b);
for(int i = 19;i>=0;--i){
if(dep[fa[a][i]]>=dep[b]) a = fa[a][i];
}
if(a==b) return a;
for(int i = 19; i >=0;--i){
if(fa[a][i] != fa[b][i]) {
a = fa[a][i];
b = fa[b][i];
}
}
return fa[a][0];
}
int sum[N];
void add(int v){
for(; v <=idx; v += v&-v){
sum[v]++;
}
}
int get1(int v){
int ret = 0;
while(v>0){
ret += sum[v];
v-=v&-v;
}
return ret;
}
int get(int v){
if(v==-1) return 0;
return get1(out[v]) - get1(in[v]-1);
}
int get_a(int f, int v){
if(v==f)return -1;
for(int i = 19;i >=0;--i){
if(dep[fa[v][i]] >=dep[f]+1){
v = fa[v][i];
}
}
return v;
}
int main(){
int n,m;
cin>>n;
fr(i,0,n-1){
int u,v;
sf("%d%d",&u,&v);
g[u].pb(v);
g[v].pb(u);
}
idx = 1;
dfs(1,1);
cin>>m;
vector<int> pos;
fr(i,0,m){
sf("%d%d",&a[i],&b[i]);
if(dep[a[i]] > dep[b[i]]){
swap(a[i],b[i]);
}
else if(dep[a[i]] == dep[b[i]]){
if(in[a[i]] > in[b[i]]){
swap(a[i],b[i]);
}
}
la[i] = lca(a[i],b[i]);
pa[i] = get_a(la[i],a[i]);
pb[i] = get_a(la[i],b[i]);
pos.pb(i);
}
auto cmp = [&](int i, int j){
return dep[la[i]]<dep[la[j]];
};
sort(pos.begin(), pos.end(), cmp);
int last = 0;
ll ans = 0;
for(int i = 0; i < pos.size();++i){
while(last<pos.size() && dep[la[pos[last]]] < dep[la[pos[i]]]){
int idx = pos[last++];
add(in[a[idx]]);
add(in[b[idx]]);
}
int idx = pos[i];
int tot = get(la[idx]);
int ask = get(pa[idx]);
ask += get(pb[idx]);
ans += tot - ask;
}
map<int, vector<pair<int,int> >> p;
for(int i = 0; i < pos.size();++i){
int idx = pos[i];
int pa = get_a(la[idx],a[idx]);
int pb = get_a(la[idx],b[idx]);
if(pa>pb)swap(pa,pb);
p[la[idx]].pb(mp(pa,pb));
}
ll ans2 = 0;
for(auto it : p){
map<int,int> ft;
map<pair<int,int>,int > ftt;
auto&vec = it.second;
ll tot = 0;
for(auto x : vec) {
ans2 += tot - ft[x.first] - ft[x.second] + ftt[x];
if(x.first>=0)
ft[x.first]++;
if(x.second>=0)
ft[x.second]++;
if(x.first>=0&&x.second>=0)
ftt[x]++;
tot++;
}
}
cout<<ans+ans2<<endl;
}