8 29 最後一英里

2022-04-30 08:09:07 字數 1591 閱讀 6694

給一顆根為\(1\)的有根樹,樹上每個點的權值為\(w_i\),大小為\(a_i\)

有\(q\)個詢問,給出兩個引數\(x,s\)

詢問在以\(x\)為根的子樹中,選出若干個點,這些點的大小之和不超過\(s\),並最大化權值之和

乙個明顯的\(o(ns^2)\)的樹形揹包暴力

設\(f[x][k]\)為以\(x\)為根的子樹中大小和小於\(k\)的結點的最大權值和,轉移也很顯然

我們可以發現對於乙個點\(x\),它的狀態是由所有子節點的狀態合併轉移過來的

於是可以考慮啟發式合併的小\(trick\)

把整棵樹進行輕重鏈剖分,對於乙個節點,先把它重兒子的狀態複製上去,對於輕兒子暴力轉移:具體來說,就是把輕兒子為根的子樹中的每個節點視作乙個物品,揹包即可

有兩種證明複雜度是\(o(nslogn)\)的方法:

第一種:

考慮啟發式合併時,每次合併以後子樹大小至少變為原來的兩倍,所以每個節點最多被合併\(logn\)次。合併單個節點的複雜度是\(o(s)\)的,所以總複雜度為\(o (nslogn)\)

第二種:

考慮輕重鏈剖分的性質,對於任意乙個節點,其到根節點的路徑上有\(logn\)級別個輕路徑,因此每個節點最多被合併\(logn\)次。所以複雜度得證

記住對於這類題目的模型:

樹上的問題,狀態由子節點狀態合併轉移而來,可以考慮輕重鏈剖分啟發式合併,重兒子狀態直接繼承,輕兒子狀態暴力轉移

#include #include #include using namespace std;

int read();

const int n = 4e5 + 10;

int n, q;

int w[n], a[n];

int cap;

int head[n], to[n << 1], nxt[n << 1];

int sz[n], son[n];

long long f[5010][5010];

inline void add(int x, int y)

inline long long max(long long x, long long y)

void dfs3(int x, int fa, long long *f)

}void dfs2(int x, int fa)

memcpy(f[x], f[son[x]], sizeof f[son[x]]);

for (int i = head[x]; i; i = nxt[i])

for (int i = 5000; i >= a[x]; --i) f[x][i] = max(f[x][i], f[x][i - a[x]] + w[x]);

}void dfs(int x, int fa)

}int main()

for (int i = 1; i <= n; ++i)

scanf("%d%d", w + i, a + i);

dfs(1, 0);

dfs2(1, 0);

q = read();

while (q--)

return 0;

}int read()

持續交付的最後一英里

如果開發人員的變更集在整合時並沒有實現長期部署就緒的狀態,那麼你的團隊其實就沒有真正的實踐持續交付。想要完全優化產品開發周期,你需要在團隊中強調無縫部署的重要性,使每位工程師都對主要生產線負責,使主要生產線保持在可發布狀態。真正的持續交付中很多團隊大概率都會遇到的以下三類阻礙 這篇文章將會告訴你如何...

21英里法則 解決連續交付的最後一英里問題

21英里法則 這篇文章是我們 縮短週期時間 戰術指南 共分為五個部分 的第五篇也是最後一篇文章。在此處 如果開發人員的變更集在合併時不一定總是可以部署,那麼您的團隊就沒有在實踐持續交付。完全優化產品上市時間 或週期時間 的最後一步是灌輸無縫部署,讓每個工程師負責將主要生產部門保持在可發布狀態。真正的...

解決連續交付的最後一英里問題

這篇文章是我們 縮短週期時間 戰術指南 共分為五個部分 的第五篇也是最後一篇文章。在此處 如果開發人員的變更集在合併時並非始終準備就緒,則您的團隊將不練習持續交付。完全優化產品上市時間 或週期時間 的最後一步是灌輸無縫部署,讓每個工程師負責將主要生產部門保持在可發布狀態。真正的持續交付的障礙可分為三...