1. 程式人生 > >[dfs][樹的直徑] Jzoj P1737 刪邊

[dfs][樹的直徑] Jzoj P1737 刪邊

ret desc sam void truct turn scanf 情況 insert

Description

  給出N個點,N-1條邊的連通圖.
  現要求刪除一條邊,使得連通塊的直徑總和最大.所謂連通塊的直徑是指連通塊中最遠兩點之間的距離。
     問:直徑總和最大是多少?

Input

  文件名為 delete.in
  第一行正整數N.
  接下來N-1行.每行兩個數,A,B,LEN表示A,B(1<=A,B<=N)有一條長度為Len(1<=Len<=1000)的邊連接著.

Output

  文件名為 delete.out
  一個數Ans.直徑總和的最大值.

Sample Input

10
2 1 982
3 1 169
4 1 934
5 1 325
6 1 735
7 1 675
8 2 302
9 3 450
10 5 173
 

Sample Output

2668

Data Constraint

Hint

【數據範圍】
  30% N<=100
  70% N<=5000
  100% N<=100000

題解

  • 首先,我們要預處理出每一棵子樹的直徑和子樹中的最遠點,次遠點和子樹中過x的最長鏈、次長鏈和次次長鏈
  • 那麽考慮刪去一條邊後直徑有哪幾種情況
  • ①在x的子樹裏
  • ②在x上面的聯通塊的直徑
  • ③x子樹沒被刪去的最遠點與x上方最遠點的和
  • ④在x不同子樹上最遠的點的和
  • 那麽考慮一下怎麽求:
  • ①預處理得出
  • ②在遞歸時可以記錄當前經過聯通塊的最大值
  • ③x子樹裏的在預處理裏已經求出來,那麽不在x子樹裏的也就是遞歸經過x的最長鏈
  • ④也就是在x子樹裏不含被刪子樹的最遠點和次遠點

代碼

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 struct edge { int to,from,v; }e[100010*2];
 5 int mx[2][100010][4
],d[2][100010][4],fa[100010],head[100010],dis[100010],ans,n,cnt; 6 void insert(int x,int y,int z) { e[++cnt].to=y; e[cnt].v=z; e[cnt].from=head[x]; head[x]=cnt; } 7 void dfs(int x) 8 { 9 for (int i=head[x];i;i=e[i].from) 10 { 11 int v=e[i].to; 12 if (v!=fa[x]) 13 { 14 fa[v]=x; 15 dfs(v); 16 dis[x]=max(dis[x],dis[v]); 17 if (dis[v]>mx[0][x][1]) 18 { 19 mx[0][x][2]=mx[0][x][1]; 20 mx[0][x][1]=dis[v]; 21 d[0][x][1]=v; 22 } 23 else if (dis[v]>mx[0][x][2]) mx[0][x][2]=dis[v]; 24 int vis=mx[1][v][1]+e[i].v; 25 if (vis>mx[1][x][1]) 26 { 27 mx[1][x][3]=mx[1][x][2]; 28 mx[1][x][2]=mx[1][x][1]; 29 mx[1][x][1]=vis; 30 d[1][x][2]=d[1][x][1]; 31 d[1][x][1]=v; 32 } 33 else 34 if (vis>mx[1][x][2]) 35 { 36 mx[1][x][3]=mx[1][x][2]; 37 mx[1][x][2]=vis; 38 d[1][x][2]=v; 39 } 40 else if (vis>mx[1][x][3]) mx[1][x][3]=vis; 41 } 42 } 43 dis[x]=max(mx[1][x][1]+mx[1][x][2],mx[0][x][1]); 44 } 45 void find(int x,int a,int b) 46 { 47 int mx1,mx2,mx3; 48 if (x!=1) ans=max(ans,dis[x]+a); 49 for (int i=head[x];i;i=e[i].from) 50 { 51 int v=e[i].to; 52 if (v!=fa[x]) 53 { 54 if (d[1][x][1]==v) 55 { 56 mx1=mx[1][x][2]; 57 mx2=mx[1][x][2]+mx[1][x][3]; 58 } 59 else 60 { 61 mx1=mx[1][x][1]; 62 if (d[1][x][2]==v) mx2=mx[1][x][1]+mx[1][x][3]; else mx2=mx[1][x][1]+mx[1][x][2]; 63 } 64 if (d[0][x][1]==v) mx3=mx[0][x][2]; else mx3=mx[0][x][1]; 65 find(v,max(max(a,mx3),max(mx1+b,mx2)),max(b,mx1)+e[i].v); 66 } 67 } 68 } 69 int main() 70 { 71 scanf("%d",&n); 72 for (int i=1;i<=n-1;i++) 73 { 74 int x,y,z; 75 scanf("%d%d%d",&x,&y,&z); 76 insert(x,y,z); insert(y,x,z); 77 } 78 dfs(1); 79 find(1,0,0); 80 printf("%d",ans); 81 return 0; 82 }

[dfs][樹的直徑] Jzoj P1737 刪邊