oiclass3904 種樹 樹形DP 換根

2022-09-10 16:00:45 字數 923 閱讀 7996

題目

題面bluesky007喜歡種樹。一天,她得到了一棵\(n\)個點的樹,其中節點\(i\)重量為\(w_i\) 。在種樹之前,bluesky007需要用起重機把樹吊起。由於她只有一台起重機,所以她只能選擇乙個點作為受力點。根據bluesky007所在世界的物理知識,吊起一棵樹需要做的功為\(\sum_^w_i\cdot dis_i\),其中\(dis_i\)表示節點\(i\)與受力點之間的距離(邊數)。

由於吊起這棵樹的費用與所做的功正相關,所以bluesky007希望所做的功盡可能小。請你幫助她求出吊起這棵樹所做的功的最小值。

題解本題是裸的換根dp,很好實現。設以1為根結點,dep[u]表示u到根的路徑長度,size[u]表示以u為根的子樹中所有結點的重量和,當以1為根結點時,dfs一遍求出總做功的值,即\(sum=\sum w[u]*dep[u]\)。接著考慮換根帶來的影響,當根從u換到兒子結點v時,v所在的子樹少做功size[v],v外的結點多做功size[1]-size[v],即\(sum'=sum-size[v]+(size[1]-size[v])=sum-2*size[v]+size[1]\)。

要使\(sum'\leq sum\),則\(sum-2*size[v]+size[1]\leq sum\),即\(size[1]\leq 2*size[v]\),所以在換根時,只有滿足\(2*size[v]\geq size[1]\)的兒子結點v才可能使得總做功值變小,可以利用這個條件進行剪枝。

**#includeusing namespace std;

const int n=2*1e5+5;

int n,w[n];

long long size[n],dep[n],sum,ans=1e18;

vectorg[n];

void dfs(int u,int fa)

}int main()

for(int i=1,u,v;i

2017種樹題解

每棵樹的費用為 cost i sum x i x k 由於 x i 與 x k 的大小關係的存在,我們可以把它分成兩部分 sum x i x k x i x k,1 le k le i 1 sum x k x i x i x k,1 le k le i 1 上面 1 式繼續展開 sum x i su...

洛谷1250 種樹

一條街的一邊有幾座房子。因為環保原因居民想要在路邊種些樹。路邊的地區被分割成塊,並被編號為1.n。每個塊大小為乙個單位尺寸並最多可種一棵樹。每個居民想在門前種些樹並指定了三個號碼b,e,t。這三個數表示該居民想在b和e之間最少種t棵樹。當然,b e,居民必須保證在指定地區不能種多於地區被分割成塊數的...

洛谷1484 種樹

cyrcyr今天在種樹,他在一條直線上挖了n個坑。這n個坑都可以種樹,但為了保證每一棵樹都有充足的養料,cyrcyr不會在相鄰的兩個坑中種 樹。而且由於cyrcyr的樹種不夠,他至多會種k棵樹。假設cyrcyr有某種神能力,能預知自己在某個坑種樹的獲利會是多少 可能為負 請你幫助他 計算出他的最大獲...