解題思路
又是一道solpe trick題,觀察出影象變化後不找一些性質還是挺難做的。
首先令 \(dp[u][i]\) 為節點 \(u\) 極其子樹所有葉子到 \(u\) 距離為 \(i\) 的最少代價,顯然有
\[dp[u][i]=\sum_\min_\
\]定義函式
\[f_u(x)=dp[u][x] , g_u(x)= \min_\
\]可以得到 \(f_u(x) = \sum_ g_v(x)\) 。
不難證明,\(f,g\) 的影象都是乙個下凸包,且相鄰的段之間斜率變化為 \(1\) ,考慮由 \(f_u(x)\) 到 \(g_u(x)\) 的過程
令 \(l, r\) 為 \(f_u\) 最下面那條邊的左右端點,\(len=c(fa[u],u)\) ,把過程看做對影象的操作,那麼有:
\[g_u(x)=
\begin
f_u(x)+len& xr+len
\end
\]考慮維護這個凸包的拐點,1,2,3操作合起來相當於刪除凸包上 \(l,r\) 兩個拐點,然後插入 \(l+len,r+len\) 這兩個拐點。
4操作只需要在之前把斜率 \(\geq1\) 的拐點刪除到只剩乙個即可,不難證明對於非葉子節點,這樣的拐點只有兒子數量 \(-1\) 個,刪完之後要找的 \(l,r\) 就是當前最右邊的兩個拐點。
那麼對於每乙個 \(u\) 只需要將所有兒子的 \(g\) 合併起來即可得到當前的 \(f\) ,可並堆/線段樹合併實現都是 \(\mathcal o((n+m)\log n)\)。
我們維護出來 \(f_1\) 的所有拐點之後,求答案只需要用 \(f_1(0)\) 的值減去所有斜率 \(\leq0\) 的拐點的橫座標即可。
code
/*program by mangoyang*/
#include #include #define inf (0x7f7f7f7f)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template inline void read(t &x)
const int n = 1000005;
ll ans;
int fa[n], len[n], deg[n], n, m;
__gnu_pbds::priority_queuepq[n];
int main()
for(int i = n + m; i > 1; i--)
pq[fa[i]].push((ll) x + len[i]);
pq[fa[i]].push((ll) y + len[i]);
pq[fa[i]].join(pq[i]);
} for(int i = 1; i <= deg[1]; i++) pq[1].pop();
while(!pq[1].empty())
ans -= pq[1].top(), pq[1].pop();
cout << ans << endl;
return 0;
}
APIO2016 煙火表演
1.x l f x f x w 2.l x l w f x f l w x l 3.l w x r w f x f l 4.r w x f x f l x r w 意思是當前節點考慮到父親的那條邊權為w的邊對於不同x取值的轉移,l,r 表示最小代價的左右端點,而因為在葉子節點初始化只有乙個點 實際上...
Loj 2568 APIO2016 烟花表演
烟花表演是最引人注目的節日活動之一。在表演中,所有的烟花必須同時 為了確保安全,烟花被安置在遠離開關的位置上,通過一些導火索與開關相連。導火索的連線方式形成一棵樹,烟花是樹葉,如圖 1所示。火花從開關出發,沿導火索移動。每當火花抵達乙個分叉點時,它會擴散到與之相連的所有導火索,繼續燃燒。導火索燃燒的...
APIO2016 亞瑟王之宮
暴力 一開始看到這題 暴搜?剪枝?貪心?不知所措,但是想了一想,肯定是要預處理出每個騎士到每個點的最短路的。然後打完第三題有來做這題,發現r和c很小,那麼可以暴力出兩個點對,然後分配騎士到兩個點對去,使得答案最小。dp是肯定可以做的。貪心 現在搜到了點對i和j,假設所有的騎士都去i,每個騎士的貢獻是...