APIO2016 烟花表演

2022-03-31 16:19:24 字數 1659 閱讀 2698

解題思路

又是一道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,每個騎士的貢獻是...