CF1486F
简单题。
树上路径相交有个很经典的性质:如果 \((u_1,v_1),(u_2,v_2)\) 相交,则一定在 \(\operatorname{lca}(u_1,v_1),\operatorname{lca}(u_2,v_2)\) 中更深的那个相交。所以只用看两条路径是否除了这个点没有其他交点即可。
考虑在 \(u\to v\) 路径上 \(\operatorname{lca}(u,v)\) 的前一个和后一个点分别为 \(x,y\),简单容斥,则我们要计算的就是:设 \(w=\operatorname{lca}(u,v)\),经过 \(w\) 的路径有 \(a\) 条,经过 \(u,x\) 和 \(u,y\) 的路径分别有 \(b,c\) 条,经过 \(u,x,y\) 的路径有 \(d\) 条。则 \(ans=a-b-c+d\)。
其中 \(a,b,c\) 树剖+BIT 维护,\(d\) 开个 map 维护。
code:
点击查看代码
int n,m;
int fa[N],dep[N],siz[N],son[N];
int cur,dfn[N],rk[N],top[N];
map<ll,int> c;
int tot,head[N];
struct node{int to,nxt;}e[N<<1];
struct Node{int u,v,w;}d[N];
il void add(int u,int v){e[++tot]={v,head[u]},head[u]=tot;}
void dfs1(int u,int f){
fa[u]=f,dep[u]=dep[f]+1,siz[u]=1;
go(i,u){
int v=e[i].to;
if(v==f)continue;
dfs1(v,u),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int t){
rk[dfn[u]=++cur]=u,top[u]=t;
if(!son[u])return;
dfs2(son[u],t);
go(i,u){
int v=e[i].to;
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
struct BIT{
ll tr[N];
#define lb(x) (x&(-x))
il void upd(int x,int y){while(x<=n)tr[x]+=y,x+=lb(x);}
il ll qry(int x){ll ret=0;while(x)ret+=tr[x],x-=lb(x);return ret;}
il void update(int l,int r){
if(l>r)return;
upd(l,1);if(r<n)upd(r+1,-1);
}
}T,R;
il int getLca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
il int getSon(int u,int v){
if(u==v)return 0;
int lst=0;
while(top[u]!=top[v])lst=top[u],u=fa[top[u]];
if(u==v)return lst;
return rk[dfn[v]+1];
}
il void update(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
T.update(dfn[top[u]],dfn[u]);
R.update(dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
if(dfn[u]>dfn[v])swap(u,v);
T.update(dfn[u],dfn[v]);
R.update(dfn[u]+1,dfn[v]);
}
il bool cmp(Node x,Node y){return dep[x.w]<dep[y.w];}
void Yorushika(){
scanf("%d",&n);
rep(i,1,n-1){
int u,v;scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs1(1,0),dfs2(1,1);
scanf("%d",&m);
rep(i,1,m){
scanf("%d%d",&d[i].u,&d[i].v);
d[i].w=getLca(d[i].u,d[i].v);
}
sort(d+1,d+m+1,cmp);
ll ans=0;
rep(i,1,m){
int u=d[i].u,v=d[i].v,w=d[i].w;
ans+=T.qry(dfn[w]);
int x=getSon(u,w),y=getSon(v,w);
if(x>y)swap(x,y);
ans-=R.qry(dfn[x])+R.qry(dfn[y]);
if(x)ans+=c[1ll*x*n+y];
update(d[i].u,d[i].v);
if(x)c[1ll*x*n+y]++;
}
printf("%lld\n",ans);
}
signed main(){
int t=1;
// scanf("%d",&t);
while(t--)
Yorushika();
}