【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.一条路径的在另一条上:
对于这种情况我们显然是要统计路径上有多少个
当然可以用树剖每次统计
但我们考虑一种更优的做法
我们对每个点维护一个表示它到根上有多少个,
那么
显然对于每个只会对其子树产生+的贡献
那在序上区间修改单点查询(可以用差分树状数组变成单点修改区间查询)
2.一条路径的不在另一条上(一条路径直接穿过了另一条):
那我们考虑差分:
在处分别+,处,那答案就是的子树和了(想想为什么)
那树状数组单点修改区间查询就可以了
#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';
}
}