noip 2015 運輸計畫

2021-08-09 16:48:40 字數 2710 閱讀 1556

去題面的傳送門

題目的意思是:求將一棵樹上的任意一條邊權賦值為0時,所有航線的最長長度的最小值

想到二分答案

如何驗證?

既然我們二分的答案是最長路線,也就是說,在將一條邊權賦值為0之後,所有的路線長度應該都小於等於mid。但是只能刪掉一條邊,所以這條邊是所有刪邊之前長度小於mid的路線的交邊。問題轉化為,能否找到一條邊,被所有長度大於mid的路線經過。所以我們要統計每一條邊被經過的次數。統計的方法便是樹上差分了。需要把邊的資訊對映到點上面去,也就是把邊的權值對映為兒子節點的點權。在差分時,路線兩端點各+1,兩點的lca-2,從子節點一直求字首和,到根節點,便求出了每條邊的經過次數。此外,在求字首和時,如果每次都dfs一遍,可能會超時,但是父節點和子節點的序號大小是沒有關係的,不好直接遍歷。為了方便,我們求每乙個點的dfs序,由於子節點的dfs序一定大於父親節點,所以按照dfs序的大小直接for一遍求字首和。最後,把所有點權for一遍,如果存在某乙個經過次數恰好為長度大於mid的路徑的條數,切它的權值大於等於各點權與mid的最大差值(也就是說,如果去掉它,一定保證所有的路線長度不超過mid),這時mid是合法的,二分左區間,找更小的答案。

以上是我自己打的解析。

———————————————-lxt的萌萌分割線—————————————————–

來看一下dalao的題解(寫的還是蠻好的):

滿分做法:

官方正解:

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);

ps:這道題除錯了很久,最後才發現掛在了lca上。求fa陣列時,for迴圈的順序一定不要搞錯!因為父親節點的序號和子節點的序號沒有大小關係!如果把列舉節點序號放在外層迴圈,序號小的不一定是序號大的的父節點!

**:

#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,剛開始看這道題目的時候沒有什麼想法,然後就手賤點開了標籤 樹鏈剖分!於是我果斷就慫了,過了幾天,我現在又才繼續寫,發現好像也不一定需要樹鏈剖分,不過樹鏈剖分比較好寫吧可能。樹鏈剖分我只是看了看,也沒有實現了,好像就是將樹分成幾條鏈...