【问题描述】
豪哥生活在一个 n 个点的树形城市里面,每一天都要走来走去。虽然走的是比较的 多,但是豪哥在这个城市里面的朋友并不是很多。 当某一天,猴哥给他展现了一下大佬风范之后,豪哥决定要获得一些交往机会来提升交 往能力。豪哥现在已经物色上了一条友,打算和它(豪哥并不让吃瓜群众知道性别)交 往。豪哥现在 spy 了一下这个人的所有行程起点和终点,豪哥打算从终点开始走到起点与 其相遇。但是豪哥是想找话题的,他想知道以前有多少次行程和此次行程是有交集的,这 样豪哥就可以搭上话了。这个路径与之前路径的有交集数量作为豪哥此次的交往机会。 但是豪哥急着要做交往准备,所以算什么交往机会的小事情就交给你了。
【输入】 第一行一个正整数 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
【数据范围与约定】 对于 20%的数据 n, m≤2000 对于另外 20%的数据 n, m≤50000 对于另外 10%的数据 n, m≤200000 保证树形结构是一条链 对于另外 50%的数据 n, m≤200000
拿到题目的一瞬间 我就想起了之前做的一道树上差分lca来统计每个点被经过的次数(好像叫松鼠的新家来着
然而这道题好像又不一样,不能最后dfs扫一遍统计前缀和
我就YY是不是要树链剖分维护 然后怒码200行lca+树剖
成功的WA掉样例 然后就弃疗了 。。
其实正解是差不多的 发现我是少讨论了一种情况
如果两段路径有交,则其中一段路径的LCA在另外一段路径上。
然后分两种情况讨论
1)当前路径有之前的LCA
2)当前LCA在之前的路径上
对一条路径x,y,设lca=z
对于情况1
查询到x,y到根节点的lca的个数,相加起来,再减去2*z到根节点的lca的个数
修改需要给x~y区间(dfs序下)到根节点的lca的个数+1 其实就是一个单点查询+区间修改,考虑树状数组完成
对于情况2 求出z的子树前缀和
修改就在x,y上面打一个+1的标记,在z上面打一个-2的标记,这样就将整条链都+1了。
其实就是一个单点修改+区间查询,也是树状数组
草真是绕的一批
#include<bits/stdc++.h>
#define lowbit(x) x&(-x)
#define N 200005
#define M 200005
using namespace std;
struct node
{
int to,next;
}edge[2*M];
int n,tot,first[N],m;
inline void addedge(int x,int y)
{
tot++;
edge[tot].to=y;
edge[tot].next=first[x];
first[x]=tot;
}
int up[N][22],depth[N];
int st[N],ed[N],dfn,val[N];
void dfs(int now,int fa)
{
st[now]=++dfn;
up[now][0]=fa;
depth[now]=depth[fa]+1;
for(int i=1;i<=20;i++) up[now][i]=up[up[now][i-1]][i-1];
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
if(vis==fa) continue;
dfs(vis,now);
}
ed[now]=dfn;
}
int lca(int x,int y)
{
if(depth[x]<depth[y]) swap(x,y);
//x比y深
for(int i=20;i>=0;i--)
{
if(depth[up[x][i]]>=depth[y]) x=up[x][i];
}
if(x==y) return x;
for(int i=20;i>=0;i--)
{
if(up[x][i]!=up[y][i])
{
x=up[x][i];
y=up[y][i];
}
}
return up[x][0];
}
struct BIT
{
int T[N];
inline void add(int x,int delta)
{
for(int i=x;i<=n;i+=lowbit(i)) T[i]+=delta;
}
inline int query(int x)
{
int ans=0;
for(int i=x;i>0;i-=lowbit(i)) ans+=T[i];
return ans;
}
}A,B;
inline int getans(int x,int y,int z)
{
return A.query(st[x])+A.query(st[y])-2*A.query(st[z])+B.query(ed[z])-B.query(st[z]-1)+val[z];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL),cout.tie(NULL);
cin>>n;
for(int i=1;i<=n-1;i++)
{
int x,y;
cin>>x>>y;
addedge(x,y);
addedge(y,x);
}
dfs(1,0);
cin>>m;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y;
z=lca(x,y);
cout<<getans(x,y,z)<<'\n';
val[z]++;
A.add(st[z],1);
A.add(ed[z]+1,-1);
B.add(st[x],1);
B.add(st[y],1);
B.add(st[z],-2);
}
return 0;
}