1.树上差分概念
树上差分,字面意思就是在树上做差分。
所以她能干啥能,举个例子,如果题目问经过树上某个点或某个边的次数,树上差分就可以派上用场啦。
树上差分就是利用差分的性质,前缀和的思想。只对树上一部分节点进行修改。而不是暴力全改,能将O(n)的修改降为O(1)
这个在日后会经常用到,要好好学习。

2.点差分
咱们一个一个加肯定包会TLE的,但是我们在讲树上差分啊!
那么我们如何进行差分呢,差分是在一条链上的在树上怎么操作呢?唉!就是将树拆成链
如下

对路径3→6路径进行加一的操作我们先找到3和6的LCA即2,将这个路径转化为2条链,一个是2→3和5→6,如下

让后分别进行差分,红色和橙色对应上面的链

等会,为什么非要是5→6而不是2→6呢?因为2→3的路径已经将2已经加过了啊。
为什么我们用LCA呢,我们假设2种情况,第一种情况就是要加的树都在一个链上,这时候LCA就是深度最小节点的的父亲,例如对2→3进行操作。第二种就是像上述3→6拐过来,我们用LCA就可以求出这个路径的拐点,拐点就是LCA(3,6)=2。让后像上面一样拆成2条链
让后跑一遍Dfs就可以统计出来答案啦。
例题P3128 [USACO15DEC] Max Flow P
其实就是上面的点差分经典例题
这里LCA我们使用的是倍增求LCA
小技巧:
这个函数可以直接搞出来整数的log2x
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include<iostream> #include<vector> #include<cmath> using namespace std; int n,m; const int MN=5e4+15,ML=40; int fa[MN][ML],dep[MN],ml,sum[MN],ans=-1; vector<int> adj[MN]; void dfs(int u,int pre){ fa[u][0]=pre; dep[u]=dep[pre]+1; for(int i=1;i<=ml;i++){ fa[u][i]=fa[fa[u][i-1]][i-1]; } for(auto v:adj[u]){ if(v!=pre){ dfs(v,u); } } } int lca(int x,int y){ if(dep[x]>dep[y]){ swap(x,y); } for(int i=ML-1;i>=0;i--){ if(dep[fa[y][i]]>=dep[x]){ y=fa[y][i]; } } if(x==y) return x; for(int i=__lg(dep[x]);i>=0;i--){ if(fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; } } return fa[x][0]; } void dfss(int u,int fa){ for(auto v:adj[u]){ if(v!=fa){ dfss(v,u); sum[u]+=sum[v]; } } ans=max(ans,sum[u]); } int main(){ cin>>n>>m; ml=__lg(n); for(int i=1;i<n;i++){ int u,v; cin>>u>>v; adj[u].push_back(v); adj[v].push_back(u); } dfs(1,0); while (m--) { int s,t; cin>>s>>t; int l=lca(s,t); sum[s]++; sum[t]++; sum[l]--; if(l!=1){ sum[fa[l][0]]--; } } dfss(1,0); cout<<ans; return 0; }
|
双倍经验 P3258 [JLOI2014] 松鼠的新家
3.边差分
其实差不多
还是上面那个图

这回紫色使我们要访问的边,并加上1的边权。但是我们不能给边加边权不然不太好差分,我们只能把边权硬塞给点。

发现这不刚好可以拆成两条“链”吗,一个就是单独的3,一个5→6,那我们只需要sum[3]++,sum[6]–,sum[LCA(3,6)]-=2就ok啦
同样也只需要dfs1遍就可以统计出来答案啦(十分甚至九分的厉害)
至于为啥操作不同请自行用拆链的思想思考
树上差分之后用处很多的,尤其是重复的区间操作或贡献问题,有的时候其实也可用树链剖分取做(但是我不会),如果对您有帮助,请不要忘了点赞!(≧∇≦)ノ