#P2601. 路径的交

题意:

给定一棵 \(n\)\(n\le 5\times 10^5\))个点的树 一下给出 \(m\) 条路径(以\(u\to v\) 形式) 第 \(i\) 条路径要求询问前 \(i-1\) 条与他有多少相交的(点相交即为相交)

题解

妙题

考虑怎么计算答案,我们分类讨论:

  • 1.之前路径的 lca 在这条路径上
  • 2.这条路径的 lca 在之前的路径上

可以证明只有这两种情况,但是注意若两条路径的 lca 一致会算重,所以需要删掉一些多余的贡献,细节见下面计算方法。

考虑分别统计。

对于第一种情况:我们考虑对于节点 \(u\) 维护从 \(1\to u\) 的链上有多少 lca,发现对于每个 lca 只对自己的子树有贡献,所以就是子树加,用dfs序 来维护。查询的时候就是前缀和,找链上和就是很经典的拆成到根的四条链,不懂看代码。

对于第二种情况,发现是和第一种情况刚好反向,那么我们把查询和修改操作直接反转就可以了。

具体来讲的话,我们对每个点 \(u\) 维护有多少条链经过了 \(u\)。所以修改就是链上改,差分成 \(4\) 个点。

所以根据树上差分就是子树查。但是注意前面说过的会计算重复的部分,所以就把那个在 \(fa[lca(x,y)]\) 减的 \(1\) 减在 \(lca(x,y)\) 上。

code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=200005;
int tr1[N],n,m,tr2[N],pos[N],tot,dep[N],siz[N],fa[N],son[N],top[N],adj[N],nxt[N<<1],to[N<<1],cnt;
inline int lowbit(int x){
	return (x&(-x));
}
inline void addedge(int u,int v){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
void dfs(int u){
	siz[u]=1,pos[u]=++tot;
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==fa[u])continue;
		dep[v]=dep[u]+1,fa[v]=u;
		dfs(v),siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}
}
void dfs2(int u,int tp){
	top[u]=tp;
	if(!son[u])return;
	dfs2(son[u],tp);
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==fa[u]||v==son[u])continue;
		dfs2(v,v);
	}
}
inline int Lca(int u,int v){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])v=fa[top[v]];
		else u=fa[top[u]];
	}
	return dep[u]<dep[v]?u:v;
}
inline void update(int *tr,int pos,int k){
	for(;pos<=n;pos+=lowbit(pos))tr[pos]+=k;
}
inline int query(int *tr,int pos,int res=0){
	for(;pos;pos-=lowbit(pos))res+=tr[pos];return res;
}
int main(){
	n=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		addedge(u,v),addedge(v,u);
	}
	dfs(1),dfs2(1,1);
	m=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),ans=0;
		int lca=Lca(u,v);
		ans+=query(tr1,pos[u])+query(tr1,pos[v])-query(tr1,pos[lca])-query(tr1,pos[fa[lca]]);
		ans+=query(tr2,pos[lca]+siz[lca]-1)-query(tr2,pos[lca]-1); 
		update(tr1,pos[lca],1),update(tr1,pos[lca]+siz[lca],-1);
		update(tr2,pos[u],1),update(tr2,pos[v],1),update(tr2,pos[lca],-2);
		cout<<ans<<'\n';
	}
	return 0;
}
posted @ 2025-09-30 22:14  NeeDna  阅读(10)  评论(0)    收藏  举报