【WOJ3936】路径的交(dfs序+树状数组+Lca)

描述
给定一棵n个点的树 一下给出m条路径(以u-v形式) 第i条路径要求询问前i-1条与他有多少相交的(点相交即为相交)
输入
第一行一个正整数n表示节点个数。接下来n-1行,每行两个正整数分别是u,v表示节点u和v之间有连边。接下来一行一个 正整数m表示路径个数。然后有m行,每行两个正整数分别是u,v分别表示u到v之间有一条路径。
输出
输出共m行,每行一个整数,第i行表示豪哥在这条路径上获得的交往机会。
样例输入
5
1 2
1 3
3 4
3 5
4
4 5
4 2
1 3
1 2
样例输出
0
1
2
2
提示
对于100%的数据n,m≤200000

考虑到可能会有2种相交的情况:


1.一条路径的lcalca在另一条上:
。
对于这种情况我们显然是要统计路径上有多少个lcalca
当然可以用树剖每次O(log2n)O(log^2n)统计
但我们考虑一种更优的做法
我们对每个点维护一个sumsum表示它到根上有多少个lcalca
那么ans1=sumu+sumvsumlcasumfalcaans_1=sum_u+sum_v-sum_{lca}-sum_{fa_{lca}}
显然对于每个lcalca只会对其子树产生+11的贡献
那在dfsdfs序上区间修改单点查询(可以用差分树状数组变成单点修改区间查询)


2.一条路径的lcalca不在另一条上(一条路径直接穿过了另一条):

在这里插入图片描述
那我们考虑差分:

uvu、v处分别+11,lcalca2-2,那答案就是lcalca的子树和了(想想为什么)

那树状数组单点修改区间查询就可以了

#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<<'
';
	}
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366315.html