一道樹上差分的入手好題,中文題面不再贅述
讀完題後,我們發現,答案就是圖中的點被經過的最多次數,即有多少條路徑經過它,暴力期望得分20~40分,正解是什麼呢?
樹上差分+lca
沒錯,和差分的操作一樣,在區間的左端點加一,在右端點+1的位置減一,只不過放到了樹上,我們先預處理每個點的lca,之後我們發現了一些樹上差分的性質
1.假如我們現在有一條從u->v的路徑,那麼假如u和v的lca為a,那麼u->v的路徑必定可以拆分成u->a,a->v,為什麼呢?我們發現,想從u的上方到達u,必定要經過他的父親,同理,u若想到達他上面的點,必定要經過它的父節點,因為只有這條路徑連線著外面
2.乙個點只有乙個直接父節點 (我在廢話,不然怎麼叫樹??233),兩點之間只有一條路徑(看1)
然後我們每讀入一組起始點,就求一遍他們的lca,然後將兩點之間的路徑拆分成起點到lca和終點到lca,由差分的性質,兩條路徑上的點都加一,等價於起點加一,終點加一,然後劃重點了昂
,右端點加一是什麼呢?lca的父節點唄,那麼我們發現lca這個點會被算兩遍!所以我們把兩個鏈變成u->lca-1,lca->v,那麼我們找到lca後,將sum[lca]--,sum[fa[lca][0]]--,sum[u]++,sum[v]++,然後這個問題就順利解決了
最後求解就是在所有的sum中取最大
**
//by acermo
#include#include#include#include#include#includeusing namespace std;
const int m=50050;
vectorv[m*4];
int n,m,st,ed;
int dep[m],sum[m];
int fa[m][30],cnt,ans;
void built(int x,int fatt)
sum[ans]--;sum[fa[ans][0]]--;
return ;
}void getsum(int x,int fatt)
ans=max(ans,sum[x]);
return ;
}int main()
built(1,0);
for (int i=1;i<=m;i++)
getsum(1,0);
cout
}
洛谷P3128 最大流
本題當然可以用樹剖解決,而且是樹剖的模板題。但是對於本題來說,有一種更巧妙的辦法 樹上差分 類似於普通的差分,我們對於題目中的每一條路線i j,把它拆成i lca i,j j.然後將i點 j點的權值加一,將lca i,j 的權值減二 乍看起來沒什麼毛病,但是仔細想想,對lca i,j 的子樹進行字首...
洛谷3128 最大流(樹鏈剖分)
蒟蒻並不會樹上差分。所以只能用樹鏈剖分套線段樹維護。對於每條路徑,都相當於將所有經過的點 1,最後查詢最大值即可。includeusing namespace std const int maxn 5e4 10 const int maxm 1e5 10 int n,q,cnt int head m...
洛谷 P4722 最大流最快模板
題意 直接給出網路流建圖資訊,求最大流 一般的dinic演算法和isap演算法複雜度為o n 2m 此題有專門資料會卡這兩個演算法。因此一種複雜度上界在常用最大流演算法中最優的最高標號預留推進演算法 又叫hlpphlpp 其上界為o n 2 sqrt m 並且在經過優化後這種演算法在資料隨機的情況下...