題意:
給你一棵樹,從樹中取出一部分滿足:是一條鏈+一些直接連在這條鏈上的節點
求節點數最多的合法取出部分。
題解:
其實這題還是不難?
觀察到對於任意一條鏈,
只有兩種情況: 一條路走到底 or 以某個點為中轉
f[x]表示從x往下走,一路走到底的包括x的最優解,
f[x]包括x也包括father[x](將會加入它的貢獻)
觀察到以某個點為中轉的情況:
倘若某條鏈以乙個點為中轉,那麼這條鏈將無法向上產生貢獻,
若沒有,則變為第一種情況,且一定可以向上產生貢獻, 以點x為中轉的所有鏈都可以通過各個兒子的搭配得到
因此f[x]可以直接從f[son]中選取最優的來得到,
然後用f[x]來更新ans,
再選取兒子中的前2大,搭配起來加上x組成鏈,更新ans
所以dfs一遍然後輸出ans即可,複雜度o(n);
細節還是挺多的,要注意。
1 #include2using
namespace
std;
3#define r register int
4#define ac 350000
5#define acway 700000
6#define getchar() *o++
7char read[10001000],*o=read;
8int
n,m,ans;
9int
in[ac],f[ac];
10int
date[acway],head[ac],next[acway],tot;
11/*
觀察到對於任意一條鏈,只有兩種情況:
12一條路走到底 :以某個點為中轉
13f[i]表示從i往下走,一條路走到底的最優解(不包括i)(非最長鏈)
14但這樣並不方便。。。。因為要分的情況太多,
15所以f[x]表示從x往下走,一路走到底的包括x的最優解,
16f[x]包括x也包括father[x]
17觀察到以某個點為中轉的情況:
18倘若某條鏈以乙個點為中轉,那麼這條鏈將無法向上產生貢獻,
19若沒有,則變為第一種情況。且一定可以向上產生貢獻,
20以點x為中轉的所有鏈都可以通過各個兒子的搭配得到,
*/21
22 inline int
read()
2329
30 inline void upmax(int &a,int
b)31
3435 inline void add(int f,int
w)36
4142
void
pre()
4351}52
53void dfs(int x,int
fa)54
68else
upmax(maxn2,f[now]);69}
70upmax(ans,f[x]);
71 upmax(ans,maxn + maxn2 + in[x] - 3);//
同上,只不過多減乙個兒子
72 }//
因為也會包括x,所以會重複2次
7374
void
work()
7580
81int
main()
82
HAOI2009 毛毛蟲 樹形dp
試題描述 對於一棵樹,我們可以將某條鏈和與該鏈相連的邊抽出來,看上去就象成乙個毛毛蟲,點數越多,毛毛蟲就越大。例如下圖左邊的樹 圖 1 抽出一部分就變成了右邊的乙個毛毛蟲了 圖 2 輸入資料 在文字檔案 worm.in 中第一行兩個整數 n m 分別表示樹中結點個數和樹的邊數。接下來 m 行,每行兩...
haoi2009 毛毛蟲 樹形dp
這道題細節處理不少,但要ac不難 設以i節點為根節點的子樹能形成的最大的毛毛蟲長度為f i 則f i max f j i節點的孩子數 答案需要f最大和次大的兩個子樹合併,而且若合併的位置不是根節點,ans 我就是坑在了最後一點上,最後打表找到了問題 1 include2 include3 inclu...
HAOI2009 毛毛蟲 樹的直徑
在一棵樹中,一條鏈及與它直接相連的所有邊的集合稱作乙個毛毛蟲,這個子圖中的點數稱作這個毛毛蟲的大小。求一棵樹中最大的毛毛蟲。n leq 3 times10 5 設每個點的權值為 deg i 1 然後求最長路即可,答案就是 ans 2 include using namespace std const...