1. 程式人生 > 其它 >【樹上差分】P3128 [USACO15DEC]Max Flow P

【樹上差分】P3128 [USACO15DEC]Max Flow P

【樹上差分】P3128 [USACO15DEC]Max Flow P

傳送門

  • 題意

    FJ給他的牛棚的N個隔間之間安裝了N-1根管道,隔間編號從1到N。所有隔間都被管道連通了。

    FJ有K條運輸牛奶的路線,第i條路線從隔間si運輸到隔間ti。一條運輸路線會給它的兩個端點處的隔間以及中間途徑的所有隔間帶來一個單位的運輸壓力,你需要計算壓力最大的隔間的壓力是多少。

    隔間\(s_i\)\(lca(s_i,t_i)\),再到\(t_i\)這條路徑上所有的點的值都要進行加1操作。

    而如果直接沿著這條路徑對每一個結點進行+1操作,那是一個非常巨大的工作量。

    於是可以藉助差分的思想和dfs的特性來只對四個點進行修改,一個是\(t_i\)

    ,另外一個是\(s_i\),再一個是\(lca(t_i,s_i)\),還有一個是\(fa(lca(t_i,s_i))\)

    前兩者進行加一標記,後兩者進行減一操作,對lca進行減一是因為多算了一個,對lca的父親結點進行減一是因為取消這條鏈上的影響

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
#define PB push_back
using namespace std;
const int N = 5E4+500,logs = 18;
int n,m,k;
vector<int > g[N]; 
int dep[N],fa[N][logs+2],val[N];
void pre_dfs(int u,int from)
{
	dep[u] = dep[from] + 1 , fa[u][0] = from;
	for(int i = 0;fa[u][i];i++) fa[u][i+1] = fa[ fa[u][i] ][i]; 
    for(auto v:g[u])
	{
		if(v==from) continue;
		pre_dfs(v,u);
	}	
} 

int get_lca(int lowu,int u)
{
    if(dep[lowu]<dep[u]) swap(lowu,u);
	for(int i = logs;i>=0;i--) if(dep[lowu]-(1<<i)>=dep[u]) lowu = fa[lowu][i];
	if(lowu==u) return u;
    for(int i=logs;i>=0;i--) if(fa[lowu][i]!=fa[u][i]) lowu = fa[lowu][i],u = fa[u][i];
    
    return fa[u][0];			
}

int ans;
void get_ans(int u,int from)
{
	for(auto v:g[u])
	{
		if(v==from) continue;
		get_ans(v,u);
		val[u] += val[v];
	}
	ans = max(ans,val[u]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>k;
    repd(i,1,n-1)
    {
    	int u,v;
    	cin>>u>>v;
    	g[u].PB(v),g[v].PB(u);
	}
	pre_dfs(1,0);
	repd(i,1,k)
	{
		int u,v;
		cin>>u>>v;
		int lca = get_lca(u,v);
	    val[u]++,val[v]++,val[lca]--,val[ fa[lca][0] ]--;
	}
	get_ans(1,0);
	cout<<ans;
    return 0;

}