题解 洛谷P3128 【[USACO15DEC]Max Flow P】
\[\huge\mathcal{Description}
\]
日期 | 2020年8月25日 |
---|---|
编号 | \(\texttt{洛谷P3128}\) |
算法 | 最近公共祖先(LCA)、树上差分 |
来源 | \(USACO\ 2015\) |
\[\huge\mathcal{Solution}
\]
这道题目我们可以用树上差分来解决。
这是一道树上的点差分,需要统计每个点经过了多少次。
那么我们不妨使用树上差分,将每一次的路径上的点加一。
这样就可以很快得到每个点经过的次数。
再结合倍增法求出\(LCA\),最后\(DFS\)遍历整棵树,在回溯时对差分数组求和就能求得答案了。
\[\huge\mathcal{Code}
\]
#include<bits/stdc++.h>
#define MAX 50001
using namespace std;
struct Struct
{
int To;
int Next;
};
Struct Edge[2*MAX];
int TotalPoint,TotalEdge;
int Deep[MAX];
int Jump[MAX][31];
int Head[2*MAX];
int Prefix[MAX];
int Count;
int Ans;
inline void AddEdge(int U,int V)
{
Edge[Count].To=V;
Edge[Count].Next=Head[U];
Head[U]=Count++;
}
inline void Dfs(int Now,int Father)
{
register int i;
Deep[Now]=Deep[Father]+1;
Jump[Now][0]=Father;
for(i=1;(1<<i)<=Deep[Now];i++)
{
Jump[Now][i]=Jump[Jump[Now][i-1]][i-1];
}
for(i=Head[Now];~i;i=Edge[i].Next)
{
register int Next;
Next=Edge[i].To;
if(Next==Father)
{
continue;
}
Dfs(Next,Now);
}
}
inline int GetLCA(int A,int B)
{
if(Deep[A]>Deep[B])
{
swap(A,B);
}
register int i;
for(i=30;i>=0;i--)
{
if(Deep[A]<=Deep[B]-(1<<i))
{
B=Jump[B][i];
}
}
if(A==B)
{
return A;
}
for(i=30;i>=0;i--)
{
if(Jump[A][i]==Jump[B][i])
{
continue;
}
A=Jump[A][i];
B=Jump[B][i];
}
return Jump[A][0];
}
inline void GetAns(int Now,int Father)
{
register int i;
for(i=Head[Now];~i;i=Edge[i].Next)
{
register int Next;
Next=Edge[i].To;
if(Next==Father)
{
continue;
}
GetAns(Next,Now);
Prefix[Now]+=Prefix[Next];
}
Ans=max(Ans,Prefix[Now]);
}
int main(void)
{
register int i;
cin>>TotalPoint>>TotalEdge;
memset(Head,-1,sizeof(Head));
for(i=1;i<TotalPoint;i++)
{
register int U,V;
cin>>U>>V;
AddEdge(U,V);
AddEdge(V,U);
}
Dfs(1,0);
for(i=1;i<=TotalEdge;i++)
{
register int U,V;
cin>>U>>V;
register int LCA;
LCA=GetLCA(U,V);
Prefix[U]++;
Prefix[V]++;
Prefix[LCA]--;
Prefix[Jump[LCA][0]]--;
}
GetAns(1,0);
cout<<Ans<<endl;
return 0;
}
不要妄图追上西坠的太阳,而是要在黎明前就等着它!