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();
}
posted @   yinhee  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示