日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【BZOJ3252】攻略【闵可夫斯基和】【堆启发式合并】

發布時間:2023/12/4 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【BZOJ3252】攻略【闵可夫斯基和】【堆启发式合并】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:給一棵 nnn 個點的有點權的樹,你需要找 kkk 條根到葉子的路徑,使得路徑并集的權值和最大。

n≤2×105n\leq 2\times 10^5n2×105

其實就是個貪心,只是從這個角度更自然一點(

先有個顯然的 dp,設 f(u,k)f(u,k)f(u,k) 為從 uuu 往下找 kkk 條鏈覆蓋的權值最大值。

f′(u,k)=max?i=0k{f(u,i)+f(v,k?i)}+[k>0]auf'(u,k)=\max_{i=0}^k \{f(u,i)+f(v,k-i)\}+[k>0]a_uf(u,k)=i=0maxk?{f(u,i)+f(v,k?i)}+[k>0]au?

發現是個閔可夫斯基和的形式。

然后往這個方向考慮,不管怎么理解都能看出這是個凸殼。

所以合并的時候繼承葉子最多的兒子(或者直接繼承子樹最大的也可以)的凸包,其他的暴力做閔可夫斯基和。可以用堆來維護斜率也就是差分,然后暴力插入。最后把第一項 +au+a_u+au? 即可。

復雜度是 O(nlog?2n)\Omicron(n\log ^2n)O(nlog2n),但常數很小。

腦抽寫了個平衡樹,我是 SB

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <vector> #include <cstdlib> #define MAXN 200005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } typedef long long ll; int ch[MAXN][2],key[MAXN],tot; ll val[MAXN]; inline int newnode(int v){return val[++tot]=v,key[tot]=rand(),tot;} int merge(int x,int y) {if (!x||!y) return x|y;if (key[x]<key[y]) return ch[x][1]=merge(ch[x][1],y),x;return ch[y][0]=merge(x,ch[y][0]),y; } void split(int x,ll v,int& l,int& r) {if (!x) return (void)(l=r=0);if (val[x]>v) split(ch[x][1],v,l,r),ch[x][1]=l,l=x;else split(ch[x][0],v,l,r),ch[x][0]=r,r=x; } int getfir(int& x) {if (!ch[x][0]) {int t=x;x=ch[x][1],ch[t][1]=0;return t;}return getfir(ch[x][0]); } inline void insert(int& x,int v) {int l,r;split(x,val[v],l,r);x=merge(merge(l,v),r); } vector<int> e[MAXN]; int a[MAXN],rt[MAXN],lev[MAXN],son[MAXN]; void dfs(int u) {if (e[u].empty()) return (void)(lev[u]=1);for (int i=0;i<(int)e[u].size();i++){dfs(e[u][i]);if (lev[e[u][i]]>lev[son[u]]) son[u]=e[u][i];lev[u]+=lev[e[u][i]];} } void Dfs(int u) {if (son[u]) Dfs(son[u]),rt[u]=rt[son[u]];else return (void)(rt[u]=newnode(a[u]));for (int i=0;i<(int)e[u].size();i++)if (e[u][i]!=son[u]){Dfs(e[u][i]);while (rt[e[u][i]]) insert(rt[u],getfir(rt[e[u][i]]));}int p=getfir(rt[u]);val[p]+=a[u];rt[u]=merge(p,rt[u]); } int main() {int n,k;n=read(),k=read();for (int i=1;i<=n;i++) a[i]=read();for (int i=1;i<n;i++){int u,v;u=read(),v=read();e[u].push_back(v);}dfs(1),Dfs(1);ll ans=0;while (k--) ans+=val[getfir(rt[1])];cout<<ans;return 0; }

總結

以上是生活随笔為你收集整理的【BZOJ3252】攻略【闵可夫斯基和】【堆启发式合并】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。