題解 洛谷P3128 【[USACO15DEC]Max Flow P】
阿新 • • 發佈:2020-08-25
\[\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; }