洛谷3117 BZOJ4033 樹上染色 樹形揹包

2021-08-21 22:07:41 字數 1385 閱讀 8412

題目鏈結

題意:給你一棵n個點的樹,邊有邊權,要在其中選k個點染成黑色,其餘點染成白色,求所有相同顏色點之間的路徑的權值之和。

題解:這個題不難想到要樹形dp,狀態設計也還好,但是要如何設計dp含義、如何統計答案是有難度的。我們不難想到dp有一維應該設計成以x為根的子樹的情況,另一維設計成子樹內染了i個黑色點,但是如果dp陣列的含義設為子樹內的權值之和的話似乎好像很難向父節點轉移,因為多了一些新的點之後這些新的點也會與原來子樹內的點形成路徑,對答案產生影響。

所以我們應該設dp陣列的含義是以x為根的子樹裡選了k個點染成黑色的情況下子樹的路徑對整個答案的貢獻。由於我們可以處理出每個子樹的大小,所以我們確定了子樹黑點個數的情況下就可以相減得到白點個數。

這樣我們考慮每條路徑對最終答案的貢獻,一條路徑會被經過的次數可以看作從這條邊把樹分成兩半,那麼經過的次數就是左側白點的數量乘右側白點的數量加上左側黑點的數量乘右側黑點的數量(乘法原理),貢獻的話就是次數乘上權值就好了。然後我們考慮如何給子樹分配這k個黑點,做法就是樹形揹包。

值得注意的是這道題的複雜度,這個複雜度看起來是o(n

3)

o(n^3)

o(n3

)的,但是仔細考慮我們是列舉了一棵樹的所有子樹進行揹包,每次揹包序列長度是由子樹大小影響的,這個可以轉化為一棵樹的點對個數,因為任意兩點只會在他們的lca處對複雜度產生o(1

)o(1)

o(1)

的影響。做揹包時的每乙個i,j可以對應為子樹的兩個點,所以是在兩個點的lca處產生o(1

)o(1)

o(1)

的複雜度貢獻,一共n

2n^2

n2級別的點對很顯然吧(每個點都與除了自己外的所有點形成點對,n∗(

n−1)

n*(n-1)

n∗(n−1

))。這題**在bzoj上t了,但是在洛谷上跑得是很快的,不知道為什麼,弄到bzoj測評資料在本機測也是非常快的。

**:

#include using namespace std;

int n,hed[2010],cnt,k,sz[2010];

long long dp[2010][2010];

struct node

a[20010];

inline int read()

return x;

}inline void add(int from,int to,int dis)

void dfs(int x,int fa)}}

} } }

int main()

memset(dp,-0x3f,sizeof(dp));

dfs(1,0);

printf("%lld\n",dp[1][k]);

return 0;

}

洛谷 3373 線段樹

傳送門 思路 關鍵在於乘與加的先後計算關係,x y k x k y k,從這裡可以看出來,把加法轉化為乘法計算,取消了 與 先後順序 pushdown時,即為乘法標記 原有資料 加法標記 長度。注意點 這個題資料範圍取long long 讀入的k也是long long,傳入函式時用long long...

洛谷 1198 線段樹

線段樹的單點更新 區間查詢,典型的求區間最大值。如下 1 include2 using namespace std 3 typedef unsigned int ui 4 typedef long long ll 5 typedef unsigned long long ull 6 define p...

樹鏈剖分簡介(BZOJ1036)(洛谷2590)

建議學樹剖的同學先學會dfs序,並有一定的資料結構基礎 樹鏈剖分,計算機術語,指一種對樹進行劃分的演算法,它先通過輕重邊剖分將樹分為多條鏈,保證每個點屬於且只屬於一條鏈,然後再通過資料結構 樹狀陣列 sbt splay 線段樹等 來維護每一條鏈。那它有什麼用呢?它可以解決一些樹上路徑的一些問題。一般...