去題面的傳送門
題目的意思是:求將一棵樹上的任意一條邊權賦值為0時,所有航線的最長長度的最小值
想到二分答案
如何驗證?
既然我們二分的答案是最長路線,也就是說,在將一條邊權賦值為0之後,所有的路線長度應該都小於等於mid。但是只能刪掉一條邊,所以這條邊是所有刪邊之前長度小於mid的路線的交邊。問題轉化為,能否找到一條邊,被所有長度大於mid的路線經過。所以我們要統計每一條邊被經過的次數。統計的方法便是樹上差分了。需要把邊的資訊對映到點上面去,也就是把邊的權值對映為兒子節點的點權。在差分時,路線兩端點各+1,兩點的lca-2,從子節點一直求字首和,到根節點,便求出了每條邊的經過次數。此外,在求字首和時,如果每次都dfs一遍,可能會超時,但是父節點和子節點的序號大小是沒有關係的,不好直接遍歷。為了方便,我們求每乙個點的dfs序,由於子節點的dfs序一定大於父親節點,所以按照dfs序的大小直接for一遍求字首和。最後,把所有點權for一遍,如果存在某乙個經過次數恰好為長度大於mid的路徑的條數,切它的權值大於等於各點權與mid的最大差值(也就是說,如果去掉它,一定保證所有的路線長度不超過mid),這時mid是合法的,二分左區間,找更小的答案。
以上是我自己打的解析。
———————————————-lxt的萌萌分割線—————————————————–
來看一下dalao的題解(寫的還是蠻好的):
滿分做法:ps:這道題除錯了很久,最後才發現掛在了lca上。求fa陣列時,for迴圈的順序一定不要搞錯!因為父親節點的序號和子節點的序號沒有大小關係!如果把列舉節點序號放在外層迴圈,序號小的不一定是序號大的的父節點!官方正解:
1.tarjan離線求lca+二分+樹上差分;
2.樹鏈剖分+二分+樹上差分+dfs序;
ps:樹鏈剖分求lca的**量比倍增小,並且效率高, 並且不難,建議大家學一下;
說一下第二種解法:
明確:
1.我們要刪的邊一定在最長路線上;
2.我們將邊的資訊對映到點上,也就是說兒子與父親的邊的資訊,我們放在了兒子身上;
首先,最大值最小化,我們可以想到二分這個最大路線長度;
假設我們已經二分出乙個mid:刪邊後最大路線的長度;
1.所有大於mid的路線都必須刪去一條邊,使之小於或等於mid;
2.總共只能刪一條邊;
聯立1,2得:
我們要刪的邊出現在所有大於mid的線路上,刪去這條邊,原本最長的路線要等於mid,其他路線小於mid;
此時我們的mid是合法答案;
如何求一條邊被所有路線經過的次數?
樹上差分!
對於條路線,我們將它起點的邊+1,終點的邊+1,lca上面的邊-2;
最後求一遍樹上字首和,就可以得到答案;
但是,如果我們每次都從根節點dfs一遍求字首和,它的複雜度雖然是o(n),但遞迴會耗費大量時間,會被卡掉最後乙個點;所以我們考慮用dfs序來求解;
在處理樹上資訊時順便求出dfs序;
然後我們從後往前求字首和就可以了,這樣是沒有後效性的,因為我們dfs時先訪問父親,再訪問兒子,父親的dfs序必然小於它兒子的dfs序,如果從後往前,必然先更新兒子,再更新父親,複雜度是常數很小的o(n);
總複雜度:o(nlogn);
**:
#include
#include
#include
#include
#include
using
namespace
std;
const
int maxn=300000+10;
int n,m,cnt,index,l=-1,r,ans;
int fist[maxn],nxt[maxn<<1],rank[maxn],deep[maxn],dfn[maxn];
int fa[maxn][22],vpoint[maxn],cha[maxn];
struct hh
e[maxn<<1];
struct lxt
ee[maxn];
void build(int f,int t,int v)
; nxt[cnt]=fist[f];
fist[f]=cnt;
}int make_lca(int x,int y)
return fa[x][0];
}void dfs(int f,int t,int v)
}void done()
bool check(int mid)
if(!tot) return
true;
for(int i=n;i>=1;--i) cha[fa[dfn[i]][0]]+=cha[dfn[i]];
for(int i=2;i<=n;++i)
if(cha[i]==tot&&vpoint[i]>=maxx) return
true;
return
false;
}int main()
dfs(0,1,0);
done();
for(int i=1;i<=m;++i);}
while(r-l>1)
if(check(l)) ans=l;
else ans=r;
printf("%d",ans);
return
0;}
noip2015 運輸計畫
公元 2044 年,人類進入了宇宙紀元。l 國有 n 個星球,還有 n 1 條雙向航道,每條航道建立在兩個星球之間,這 n 1 條航道連通了 l 國的所有星球。小 p 掌管一家物流公司,該公司有很多個運輸計畫,每個運輸計畫形如 有一艘物流飛船需要從 ui 號星球沿最快的宇航路徑飛行到 vi 號星球去...
NOIP2015 運輸計畫
題目鏈結 codevs 4632 題目大意 在一棵 n 節點樹上,有 m個運輸計畫 從ai 到 bi n,m 300000 問 把哪一條樹邊的權值變為0,可以使所有運輸計畫的最大距離最小,輸出這個最大距離的最小值。分析 0.首先要會lca和樹上差分。1.顯然,這道題要求樹上兩點之間的距離,所以要寫l...
NOIP2015 運輸計畫
既然是noip的題目,那麼 意料之中的偷懶不可避免 actually,剛開始看這道題目的時候沒有什麼想法,然後就手賤點開了標籤 樹鏈剖分!於是我果斷就慫了,過了幾天,我現在又才繼續寫,發現好像也不一定需要樹鏈剖分,不過樹鏈剖分比較好寫吧可能。樹鏈剖分我只是看了看,也沒有實現了,好像就是將樹分成幾條鏈...