洛谷 P1099 樹網的核(樹的直徑,樹上尺取)

2022-02-13 12:52:38 字數 2631 閱讀 7031

感覺課件裡講的還是比較詳細的。

先說一下n^3做法:floyd預處理出樹中任意兩點之間的距離,然後在直徑上暴力列舉核的左右端點,再列舉每個點,則這個點到核的距離為(dis[d[i]][k]+dis[d[j]][k]-dis[d[i]][d[j]])/2。畫圖即可推出來。

o(n^3)做法原題穩過,但是我們追求更高效的做法。

o(n^2)需要用到尺取思想,在核的左端點確定時,核長度越大結果越優,這樣就可以o(n)列舉樹網的核,然後列舉樹網的和上的每個節點,對於核上的每個節點所能到達的最遠的點和核兩端到直徑兩端的距離去max,即為這個樹網的核的ecc。我們需要提前預處理出樹直徑上每個點不經過直徑所能到達的最遠點的距離。

對於o(n)做法,我們從o(n^2)做法改進,很顯然列舉樹網的核沒法優化,但我們可以用單調佇列o(1)處理出樹網的核這段區間內的最遠距離。

另外,單調佇列也可以優化掉。

我們發現這樣乙個性質,影響ecc的答案的點只有這幾個情況:

對於第乙個情況,我們列舉樹網的核時可以直接求出來;

對於第二種情況,很顯然除了離直徑最遠的點,其他的點對最終答案不會產生影響,還是可以畫圖理解。所以只需在最後取乙個max即可。

1 #include2 #include3 #include4 #include5 #include6

using

namespace

std;

7const

int maxn=305;8

int n,s,dis[maxn][maxn],m[maxn][maxn],d1,d2,d[maxn],num,ans=0x3f3f3f3f;9

bool ok(int u,int fa,int

d2)16

if(i!=fa&&m[u][i])21}

22}23return0;

24}25void findd(int d1,int fa,int

d2)32

if(i!=fa&&m[d1][i])37}

38}39}

40int

main()

4149

for(int i=0;i<=n;i++) dis[i][i]=0;50

for(int k=1;k<=n;k++)55}

56}57for(int i=1;i<=n;i++)61}

62 findd(d1,-1

,d2);

63for(int i=1;i<=num;i++)

64for(int j=i;j<=num;j++)71}

72 ans=min(ans,ecc);73}

74 cout<

75return0;

76 }

o(n^3)

1 #include2 #include3 #include4 #include5 #include6

const

int maxn=500005;7

using

namespace

std;

8int

n,s,p[maxn],d[maxn],isd[maxn],d1,d2,num,cnt,fa[maxn],maxd;

9long

long ans,anss=(long

long)10*0x3f3f3f3f

,dis[maxn],lend,disfa[maxn];

10struct

nodee[maxn*2

];13

void insert(int u,int v,int

value)

20void dfs(int u,int

faa)30}

31long

long dfsdis(int u,int fa,long

long

diss)37}

38return ans+diss;39}

40int

main()

4150 dfs(1,-1

);51 d1=maxd;

52 memset(dis,0,sizeof

(dis));

53 memset(disfa,0,sizeof

(disfa));

54 memset(fa,-1,sizeof

(fa));

55 dfs(d1,-1

);56 d2=maxd;

57for(int i=d2;i!=-1;i=fa[i])

61for(int i=1;i<=num;i++)66}

67int head=1,tail=1;68

long

long len=0,lend1=dis[d2],lend2=0;69

while(head<=num&&tail<=num)

75 anss=min(anss,max(lend1,lend2));

76 len-=disfa[d[head]];

77 lend2+=disfa[d[head]];

78 head++;79}

80 cout<

81return0;

82 }

o(n)

洛谷 P1099 樹網的核(樹的直徑 貪心)

用兩邊dfs求出直徑,用f記錄fa,這樣就記錄下了直徑的路徑,將直徑上的點vis標記為1。然後列舉左右端點 或者尺取法,但不會 貪心考慮對答案的貢獻 假設直徑的兩個端點為a和b,當前左右端點為i,j,對答案的貢獻只有a,i之間的距離 b,j之間的距離 i,j中每個節點的子樹的最遠距離。那麼可以對於直...

洛谷P1099 樹網的核

題目 對於這種題目描述比較長的題,可以考慮簡化題意。簡化後的題意 給定一棵帶邊權無根樹 在其直徑上求出一段長度不超過s的路徑f,使得離路徑距離最遠的點到路徑的距離最短。求最短距離。根據題目範圍,直接暴力floyd求多源最短路徑。然後 n 2 求出直徑和直徑端點。搜尋求出直徑上的點。然後再暴力找出所有...

洛谷 P1099 樹網的核

設t v,e,w t v,e,w 是乙個無圈且連通的無向圖 也稱為無根樹 每條邊到有正整數的權,我們稱tt為樹網 treebetwork 其中vv,ee分別表示結點與邊的集合,ww表示各邊長度的集合,並設tt有nn個結點。路徑 樹網中任何兩結點aa,bb都存在唯一的一條簡單路徑,用d a,b d a...