算法浅谈之树上差分
先放一道例题[USACO15DEC]Max Flow P
题目大意
给你一棵\(n\)个点的树,有\(k\)条管道,每条管道有个起始点和终结点。从起始点到终结点的路径上每个经过的点权值都要\(+1\)
现在问你这\(k\)条管道都处理完后权值最大的点的权值是多少
\(N\le50000\)
\(K\le100000\)
分析
乍一看有一点棘手啊。
如果是条链
我们考虑这棵树是一条链。那么就是一个正常的差分:起始点\(+1\),终结点后面的点\(-1\),最后哪一个变量从头加到尾,记录最大值。
其他情况
那就只能用树上差分来做。
树上差分。顾名思义,就是在树上进行差分操作。具体是:起始点和终止点\(+1\),LCA与LCA的父亲\(-1\)。这样就可以完成树上差分
不会LCA的请看https://www.cnblogs.com/hulean/p/11144059.html
具体为什么的话,画图就很明显了。
dfs
差分处理完后,我们只需要一遍dfs来累加每个点的值,并且维护最大值。
这道题就做完了
#include <bits/stdc++.h>
using namespace std ;
const int MAXN = 50000 + 5 ;
struct Node {
int next , to ;
} edge[ MAXN << 1 ] ;
int head[ MAXN ] , cnt ;
int n , k , w[ MAXN ] , ans ;
int deep[ MAXN ] , fa[ MAXN ][ 21 ] ;
inline int read () {
int tot = 0 , f = 1 ; char c = getchar () ;
while ( c < '0' || c > '9' ) { if ( c == '-' ) f = -1 ; c = getchar () ; }
while ( c >= '0' && c <= '9' ) { tot = tot * 10 + c - '0' ; c = getchar () ; }
return tot * f ;
}
inline void add ( int x , int y ) {
edge[ ++ cnt ].next = head[ x ] ;
edge[ cnt ].to = y ;
head[ x ] = cnt ;
}
inline void dfs ( int u , int father ) {
fa[ u ][ 0 ] = father ; deep[ u ] = deep[ father ] + 1 ;
for ( int i = 1 ; i <= 20 ; i ++ )
fa[ u ][ i ] = fa[ fa[ u ][ i - 1 ] ][ i - 1 ] ;
for ( int i = head[ u ] ; i ; i = edge[ i ].next ) {
int v = edge[ i ].to ;
if ( v == father ) continue ;
dfs ( v , u ) ;
}
}
inline int Lca ( int x , int y ) {
if ( x == y ) return x ;
if ( deep[ x ] < deep[ y ] ) swap ( x , y ) ;
for ( int i = 20 ; i >= 0 ; i -- ) {
if ( deep[ fa[ x ][ i ] ] >= deep[ y ] ) x = fa[ x ][ i ] ;
}
if ( x == y ) return x ;
for ( int i = 20 ; i >= 0 ; i -- ) {
if ( fa[ x ][ i ] != fa[ y ][ i ] ) x = fa[ x ][ i ] , y = fa[ y ][ i ] ;
}
return fa[ x ][ 0 ] ;
}
inline void work ( int u , int father ) {
for ( int i = head[ u ] ; i ; i = edge[ i ].next ) {
int v = edge[ i ].to ;
if ( v == father ) continue ;
work ( v , u ) ;
w[ u ] += w[ v ] ;
}
ans = max ( ans , w[ u ] ) ;
}
signed main () {
n = read () ; k = read () ;
for ( int i = 1 ; i < n ; i ++ ) {
int x = read () , y = read () ;
add ( x , y ) ; add ( y , x ) ;
}
dfs ( 1 , 0 ) ;
for ( int i = 1 ; i <= k ; i ++ ) {
int x = read () , y = read () ;
w[ x ] ++ ; w[ y ] ++ ;
int lca = Lca ( x , y ) ;
w[ lca ] -- ; w[ fa[ lca ][ 0 ] ] -- ;
}
work ( 1 , 0 ) ;
printf ( "%d\n" , ans ) ;
return 0 ;
}