类比于数组的差分问题的树上的差分问题,对某一条路径的点权或者边权进行频繁的全部加某个数的操作,我们结合一下lca就可以简单的解决这类问题
下面是很经典的公式:
树上点权差分:
diff[a]++,diff[b]++,diff[lca(a,b)]--,diff[fa[lca(a,b)][0]]--;
树上边权差分:
先处理差分数组最后再将边权下放就行了
diff[a]++,diff[b]++,diff[lca(a,b)]-=2;
树上任意两点的距离:dist[a] + dist[b] - 2*dist[lca(a,b)] (dist数组在这里指的是我们的根节点到该节点的路径之和)
#include
using namespace std;
const int N = 1e6+10;
int e[N],ne[N],h[N],idx;
int n;
int q[N];
int diff[N];
int depth[N],fa[N][25];
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int u,int father){
depth[u] = depth[father]+1;
fa[u][0] = father;
for(int i=1;i<=20;i++)
fa[u][i] = fa[fa[u][i-1]][i-1];
for(int i = h[u];~i;i=ne[i]){
int j = e[i];
if(j==father)continue;
dfs(j,u);
}
}
int lca(int a,int b){
if(depth[a]=0;i--)
if(depth[fa[a][i]]>=depth[b])
a = fa[a][i];
if(a==b)return a;
for(int i =20;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a = fa[a][i],b = fa[b][i];
return fa[a][0];
}
void dfs2(int u,int father){
for(int i = h[u];~i;i=ne[i]){
int j = e[i];
if(j==father)continue;
dfs2(j,u);
diff[u]+=diff[j];
}
}
int main()
{
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++)cin>>q[i];
for(int i=1;i>a>>b;
add(a,b),add(b,a);
}
dfs(1,0);
for(int i=1;i+1<=n;i++){
int a = q[i];
int b = q[i+1];
int anc = lca(a,b);
//cout<
#include
#define int long long
using namespace std;
const int N = 1e6+10;
int e[N],ne[N],w[N],h[N],idx;
int fa[N][25],depth[N];
int n,m,q;
int diff[N];
void add(int a,int b,int c){
e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
}
void dfs(int u,int father){
depth[u] = depth[father]+1;
fa[u][0] = father;
for(int i=1;i<=20;i++)
fa[u][i] = fa[fa[u][i-1]][i-1];
for(int i = h[u];~i;i=ne[i]){
int j = e[i];
if(j==father)continue;
dfs(j,u);
}
}
int lca(int a,int b){
if(depth[a]=0;i--)
if(depth[fa[a][i]]>=depth[b])
a = fa[a][i];
if(a==b)return a;
for(int i=20;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a = fa[a][i],b = fa[b][i];
return fa[a][0];
}
void dfs1(int u,int father){
for(int i =h[u];~i;i=ne[i]){
int j = e[i];
if(j==father)continue;
dfs1(j,u);
diff[u]+=diff[j];
}
}
void dfs2(int u,int father){
for(int i =h[u];~i;i=ne[i]){
int j = e[i];
if(j==father)continue;
diff[j]+=w[i]+diff[u];
dfs2(j,u);
}
}
int dist(int a,int b){
return diff[a]+diff[b]-2*diff[lca(a,b)];
}
signed main()
{
cin>>n>>m>>q;
memset(h,-1,sizeof h);
for(int i=1;i>a>>b>>c;
add(a,b,c),add(b,a,c);
}
dfs(1,0);
while(m--){
int a,b,c;
cin>>a>>b>>c;
diff[a]+=c;
diff[b]+=c;
diff[lca(a,b)]-=2*c;
}
dfs1(1,0);
dfs2(1,0);
while(q--){
int a,b;
cin>>a>>b;
cout<
虽然都是板子题目,也算是解决了关于这个知识的学习~
所以树上差分是典型的数据结构题目,肯定会结合一下lca~