树上差分入门例题
树上差分入门
P3128 [USACO15DEC]Max Flow P
洛谷P3128
提示:以下是本篇文章正文内容,下面案例可供参考
一、题目大意
从s到t每一个地方都会增加一个压力,我们需要找出最大的压力。表达能力是什么,不存在的
二、思路
看了洛谷的题解才知道要用到树上差分。
什么是树上差分?
树上差分是什么?
怎么用
我个人的理解:
树上差分的应用:
1.找被所有路径共同覆盖的边。
sum[s]++,sum[t]++,sum[LCA(s,t)]-=2
2.将路径上的所有点权值加一,求最后点的权值。(这道题)
sum[u]++,sum[v]++,sum[LCA(u,v)]–,sum[f[LCA(u,v)][0]]–
代码:
#include <iostream>
#include <cstdio>
#include <stdlib.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int f[maxn][30];
int n,k,s,t;
int head[maxn],cnt;
struct edge
{
int next,to;
}e[maxn<<1];
int sum[maxn],ans;
int dep[maxn];
void add (int u,int v)
{
e[++cnt].next=head[u];
e[cnt].to=v;
head[u]=cnt;
return ;
}
void dfs(int u,int fa)
{
dep[u]=dep[fa]+1;
f[u][0]=fa;
for (int i=1;(1<<i)<=dep[u];i++)
{
f[u][i]=f[f[u][i-1]][i-1];
}
for (int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if (v==fa) continue;
dfs(v,u);
}
return ;
}
int lca(int u,int v)//这里是一个lca的模板
{
if (dep[u]<dep[v]) swap(u,v);
for (int i=20;i>=0;i--)
{
if ((1<<i)<=dep[u]-dep[v])
{
u=f[u][i];
}
}
if (u==v) return u;
for (int i=20;i>=0;i--)
{
if (f[u][i]!=f[v][i])
{
u=f[u][i];
v=f[v][i];
}
}
return f[u][0];//u的父节点
}
void getmax(int u,int fa)//找出最大的
{
for (int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if (v==fa) continue ;
getmax(v,u);
sum[u]+=sum[v];
}
ans=max(ans,sum[u]);
return ;
}
int main ()
{
scanf ("%d%d",&n,&k);
for (int i=1;i<n;i++)
{
int u,v;
scanf ("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,0);
while (k--)
{
scanf ("%d%d",&s,&t);
int fa=lca(s,t);//第二种应用
sum[s]++;
sum[t]++;
sum[fa]--;
sum[f[fa][0]]--;
}
getmax(1,0);
printf ("%d\n",ans);
system("pause");
return 0;
}
总结
这是我做的第一道树上差分的题,写这个的时候还不记得lca了,看来这些还是要多写写,背一背。
欢迎大家指教!