关于lca的基本操作看这里ovo
了解过lca就可以看看树上差分辣
大概就是通过dfs和lca来处理的,可以实现在某一子树或某一条链上加同一个数后查询每个点的值
所以显然分为两种
第一种是把某一子树全部加d
我也觉得丑
以2为底的子树全部加d,运用差分的思想,可以在它的根节点加d,处理每个节点的值是它父节点的前缀和
比如。。这个图上2.5.6.8.9.10.11全都加d,可以2加d,对每个点递归求父节点的前缀和。
第二种是求一条链上加d
依然丑
(点)5.2.6.11全部加d。考虑如果依然使用上述的方法,取父节点前缀和,那么2+d后,整颗子树全部加d
可是可是可是!8.9.10不需要加鸭!!这就比较玄学辽。
所以我们要采取另一种思路,取子节点的前缀和。
先假设一种简单的情况:求(点)2 5加d。按照差分的思想,可以把5上加d,1上减d,从下往上取子节点前缀和。
模拟这个过程。5+d,1-d。5=5+8(5上加了d),2=6+5(2上加了d),1=1+2(1上加了d又减了d,不变)。所以可以发现,从下往上真是太机智辽!!!
回到刚才的问题。5到11的一条链。显然可以使用lca把它分成5到2和2到11两条链owo。依然这么处理。
模拟一下5+d,1-d,11+d,1-d。5=5+8(5上加了d),2=6+2(2上加了d)6=6+11(6上加了d),2=6+2(2上又双叒叕加了d)(等会看1)
既然最后是高贵的粉色,说明肯定有问题。因为2上加了2个d,它只需要1个,所以能发现lca处加了2遍,于是lca要减一个d
处理完了上一个问题。继续。1=2+1(1上加一个d,减2个d)但是!!可以发现!!又粉了!!因为它不需要变,所以发现要在lca的父节点再+一个d。减2个加1个就是减1个,所以只需要lca的父节点减d。
总结就是lca-d,lca的爸爸-d,两个点+d。
代码是下边那个,例题是标题里的最大流(代码就是那个题)。
完啦!!!!!!撒花花
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
struct node
{
int nxt;
int to;
}edg[200001];
int head[50001];
int d[50001];
int fa[50001][20];
int dep[50001];
int ans,k,n,num;
void add(int ff,int ee)
{
edg[++num].to=ee;
edg[num].nxt=head[ff];
head[ff]=num;
}
void dfs(int x,int f)
{
fa[x][0]=f;
dep[x]=dep[f]+1;
for(int i=1;(1<<i)<=dep[x];i++)
{
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(int i=head[x];i;i=edg[i].nxt)
{
if(edg[i].to!=fa[x][0])
{
dfs(edg[i].to,x);
}
}
}//lca基本操作
int lca(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int i=log2(dep[y]);i>=0;i--)
{
if(dep[x]<=dep[y]-(1<<i))
y=fa[y][i];
}
if(x==y)return x;
for(int i=log2(dep[y]);i>=0;i--)
{
if(fa[y][i]!=fa[x][i])
{
y=fa[y][i];
x=fa[x][i];
}
}
return fa[x][0];
}//lca基本操作
int anss(int s)
{
for(int i=head[s];i;i=edg[i].nxt)
{
if(edg[i].to!=fa[s][0])
{
anss(edg[i].to);
d[s]+=d[edg[i].to];
}
}
if(d[s]>ans)ans=d[s];
}//s及以下的子节点前缀和
int main()
{
cin>>n>>k;
for(int i=1;i<=n-1;i++)
{
int a;int b;
cin>>a>>b;
add(a,b);add(b,a);//双向边
}
dfs(1,1);
for(int i=1;i<=k;i++)
{
int a;int b;
cin>>a>>b;
int llca=lca(a,b);
d[a]++;d[b]++;
d[llca]--;
d[fa[llca][0]]--;
}//lca--,lca的爸爸--,a、b++;
anss(1);//这样就可以算出最大值
cout<<ans;
}
某个链上全部加d,求子树的前缀和
子树全部加d,求父节点的前缀和
dfs处理