原題:poj-1741
題意:
有一棵n個節點的樹,每條邊都有乙個權值,問有多少個節點之間的距離小於等於k,
解析:
典型的樹分治,對於每一棵樹,我們首先找到它的重心
重心:一棵樹中以這個點為root時的最大子樹的節點數最小
然後計算和這個節點有關的題目中要求的東西,然後就可以刪除這個點,變成很多棵樹,在對每棵子樹進行同樣的操作int siz[n]
,maxn[n]
;//這棵子樹大小,最大子樹大小
void
getg
(int p,
int fa,
int sum)
} maxn[p]
=max
(maxn[p]
,sum-siz[p]);
//當然還要這棵樹的上半部分比較
if(maxn[g]
>maxn[p]
)g=p;
}
其他的就看題目寫了
例如:len<=k的計算過程
我們可以快速算出以a點作為中間點或是端點的點對有幾對滿足要求
假設b到a的距離+g到a的距離<=k,那麼在陣列中相應的兩個len即滿足要求,所以轉化為len陣列有幾對<=k,這個只需要排序後用兩個指標遍歷一下就可以了(需要把自己:0加進去)
但是這個時候,假設ad+ae<=k,那麼我們也是算了的,但是其實不存在dbabe,而是dbe,所以再刪除乙個部分即可int
cal(
int p,
int length)
return sum;
}
\,\\\,
\,\\\,
**:
const
int n =
10009
;int n,k;
int head[n]
,nex[
2*n]
,to[
2*n]
,from[
2*n]
,v[2
*n],now;
void
add(
int a,
int b,
int vv)
int ans;
int g;
int vis[n]
;//是否刪除
int siz[n]
,maxn[n]
;//這棵子樹大小,最大子樹大小
void
getg
(int p,
int fa,
int sum)
} maxn[p]
=max
(maxn[p]
,sum-siz[p]);
//當然還要這棵樹的上半部分比較
if(maxn[g]
>maxn[p]
)g=p;
}int dep[n]
,num,len[n]
;void
dfs(
int p,
int fa)
}int
cal(
int p,
int length)
return sum;
}void
divide
(int p)
}int
main()
}
POJ 1741 Tree 樹的分治 點分治
題目大意 給出一顆無根樹和每條邊的權值,求出樹上兩個點之間距離 k的點的對數。思路 樹的點分治。利用遞迴和求樹的重心來解決這類問題。因為滿足題意的點對一共只有兩種 1.在以該節點的子樹中且不經過該節點。2.路徑經過該節點。對於第一種點,我們遞迴處理 第二種點,我們可以將所有子樹的節點到這個子樹的根節...
點分治(樹分治)
將原問題分解成若干相同形式,相互獨立的子問題,各個擊破 一般用來解決有關樹上路徑的統計和詢問 p4178 tree 給定一棵 n 個節點的樹,每條邊有邊權,求出樹上兩點距離小於等於 k 的點對數量。暴力做法 o n2 點分治做法 選擇乙個點作為分治中心,令其為rt做dfs。對於一條路徑path u,...
1468 Tree 樹的點分治
樓教主男人八題之一 好可怕 似乎不是很難的樣子。點分治大致是這樣 先選出乙個根 一般是重心 然後可以把兩個點之間的路徑分為經過根的和不經過根的,經過根的直接處理記錄,不經過根的遞迴處理計算。似乎還用到了容斥原理的方法。記錄經過當前根的方案數的方法是 先以當前的根為起點遍歷一遍記下di s 陣列即到根...