這幾年考了好幾次樹上問題:
NOIP2012 疫情控制(二分答案+倍增+貪心)
NOIP2013 貨車運輸(最大生成樹+倍增)
NOIP2014 聯合權值(勉強算作樹形dp的傻逼題)
NOIP2015 運輸計划(二分答案+樹上差分+最近公共祖先)
NOIP2016 天天愛跑步(樹上差分+樹上倍增)
可以說除了聯合權值外都有一定的難度,(關鍵是我不抄題解一道也做不出來)
去年沒考樹上的問題所以我感覺今年要考
樹
樹是一種極其優美的結構,樹上兩點之間有且僅有一條路徑。
在近年來oi中常出現關於樹的題目。
樹的直徑
樹的直徑就是樹中最長的一條路徑,處理方法有樹形dp和兩遍dfs或bfs
需要注意的是在存在負邊權的樹中只能用樹形dp來求直徑
1.巡邏
一道畫畫圖就能搞出來的題。。。
首先我們應該想想他讓我們修路有什么用。你隨便畫一棵樹就很容易發現,要想從一個點出發經過所有點一遍再回來,每條邊是要經過兩次的。而我們修路就是為了讓其中一些邊只走一次。
$K=1$:顯然我們隨意連一條邊會形成一個環,環上的邊我們只用經過一次。這樣我們最大化環的的長度就行,也就是找到樹的直徑。
$K=2$:首先我們肯定還是連直徑。但是第二條邊怎么連?顯然我們還可以找次長鏈出來。但如果兩條鏈有重疊怎么辦?
我們可以把第一條鏈在算完長度后將所有邊權賦成-1,這樣就不會算重了。設兩次選的邊長度分別為$l1$,$l2$,那么答案就是$2*n-l1-l2$。
2.消防
首先我們應該想到這條路徑一定在樹的直徑上。這里給出證明:
設直徑的長度為$d$,那么直徑外的邊長度一定小於等於$d/2$(否則該路徑會與直徑的一部分構成一條比直徑還長的路徑)
若該路徑不在直徑上,則直徑的最遠點到該路徑的距離至少為$d/2$
而如果在直徑上,一定存在一段路徑使得樹上所有點的距離到它不超過$d/2$
所以選在直徑上一定是優的,而且在符合題目要求的情況下越長越好。
那么如果我們確定里直徑,我們可以$O(n)$求出直徑上每個點到最遠點的距離,然后左右指針掃直徑,單調隊列維護區間最小值即可。
3.直徑
求直徑的長和直徑並的數量。
直徑當然好求,而直徑並,一定是在一條直徑上。
所以我們可以先求出一條最長鏈。而所有直徑的並一定是最長鏈上連續的一段。
證明很簡單:如果中間有分開而最后又和在一起,顯然會形成一個環。
然后我們對於最長鏈上的每個點,dfs求出其子樹中距離最遠的點,若兩點之間的距離等於該點到直徑一個端點的距離,那么顯然這個點到端點之間這一段就不能用來統計答案了,將它們從答案中刪除即可。
然后我們可以正着做一遍這個操作,反向再做一遍,中間沒被刪除部分即為直徑的並
樹上管理問題
樹上的每個點能管理相鄰一片區域,求最少幾個點能管理整棵樹。
一般考慮從下往上貪心。
1.救火站Gas
又是樹上管理類的問題,我們當然考慮貪心。這個題算是消防站的設立那道題的加強版。
很顯然的一種做法是對於一個點,我們要找一個深度最小的點來覆蓋它。
然后看這個數據范圍$k<=20$,我們可以想到把他當成狀態放進數組里
設$need[i][j]$為以$i$為子樹的$j$級子孫有幾個未覆蓋,$left[i][j]$為以$i$為子樹的$j$級子孫有幾個多出來控制的沒使用
顯然當$need[i][j]$中$j=k$時,我們就必須放消防站來管理了
然后我們還可以用$left$來抵消$need$
2.消防局的設立
有一種很顯然的貪心測略:對於當前深度最大的點,我們選他的爺爺點一定是最優的。
對於最深的點我們選離他最遠但是能管理到他的祖先即可。
樹上倍增&&樹上差分
這幾年考過好幾次樹上倍增,有兩次都是和樹上差分結合在一起的。利用樹上倍增求出兩點的$LCA$,然后兩點$(u,v)$之間邊的信息往往可以轉化為$(u->root)+(v->root)-2*(LCA->root)$,點的信息可以轉化為$(u->root)+(v->root)-LCA->root-fa_LCA->root$。
1.天天愛跑步
對於每一條鏈,我們根據套路把他拆成$(u->root)+(v->root)-LCA->root-fa_LCA->root$
然后我們發現$(u->root)$和$(v->root)$要分別處理(因為一個往上走一個往下走)
設觀察員$y$出現的時間為$w_y$
那么$x$向上跑要想被觀察員看見,就要滿足等式$deep_x-w_y=deep_y$,移項得到$deep_x=deep_y+w_y$,換句話說,$y$子樹內只有滿足$deep_x=deep_y+w_y$的點會對$y$產生貢獻
當$x$向下跑想被$y$看見,我們可以設$x$的時間為$ed_x$,根據剛才的套路,我們發現子樹內只有滿足$deep_x-ed_x=deep_y-ed_y$的點會對$y$產生貢獻
用一個桶dfs一遍即可求出答案,是不是越想越簡單了。。
2.運輸計划
根據套路最大值最小的問題我們考慮二分,假設我們二分出來的答案為$mid$,那么我們顯然要把大於$mid$的所有計划減去同一條邊,且這條邊在大於$mid$的計划的路徑並上
我們差分一下求出每個計划對路徑的覆蓋,只有覆蓋數目等於大於$mid$的計划的邊可以考慮被減去
對這些可以減去的邊取一個最大值然后判斷即可
以前感覺這道題很神仙,其實仔細一分析每一步都是套路
3.疫情控制
仔細分析題目,好像還是最大值最小啊,當然是考慮二分咯。顯然我們在軍隊沒跳到首都之下的兒子上時,一直往上跳是最優的
但調到首都兒子上時,我們發現一個問題,如果接着往上跳,很可能在這個點重新需要控制的時候就跳不回來了,那還不如不跳
所以我們把所有調到首都后能返回他上一個兒子的點全部跳到首都,對於子樹內的所有葉子已經被覆蓋的軍隊當然也跳到首都,因為再留在這個點已經沒有意義了
然后我們在首都枚舉所有的葉子,如果還沒被覆蓋,就從首都派遣軍隊進行覆蓋,如果所有軍隊都到不了葉子的祖宗,自然二分的答案不合法