WC2010 重建計畫 題解

2022-08-11 18:03:14 字數 1499 閱讀 3223

​ 給定一棵樹,邊有邊權,要求找到一條長度在\([l,r]\)之間的鏈,使得鏈的總價值和除以鏈長最大

​ 顯然,這個式子的形式讓人想到了01分數規劃。於是根據01分數規劃的套路,先二分乙個答案

​ 考慮如何判斷,現在等於把所有邊都減去了乙個\(mid\),要看有沒有一條價值大於0的長度介於\([l,r]\)的鏈

​ 是不是感覺點分治呼之欲出。的確,到了這裡就是乙個點分治的經典例題了。但是這不是這篇題解的重點

​ 顯然dp也可做,記\(f_\)為在\(u\)子樹中以\(u\)為端點的一條長度為\(j\)的鏈的最大價值,這個dp轉移比較簡單,但是複雜度是\(o(n^2)\)的

​ 我們發現這個dp的第二維狀態與深度有關,故可以用長鏈剖分優化,統計答案時也可以用線段樹優化,於是複雜度優化到了\(o(nlog^2n)\)

#include#define inf 1e8

#define db double

#define eps 1e-3

using namespace std;

int n,l,r,cnt,tim;

db ans,res,f[100005],g[100005];

int head[100005],w[200005],to[200005],next[200005];

int dfn[100005],son[100005],dep[100005],sonw[100005];

struct segment_tree

void change(int k,int l,int r,int pos,db val)

db query(int k,int l,int r,int wl,int wr)

}t;inline int read()

while(ch>='0'&&ch<='9')

return x*f;

}inline void add(int u,int v,int p)

void dfs(int u,int fa)}}

return;

}void dp(int u,int fa,db x)

t.change(1,1,n,dfn[u],f[dfn[u]]);

for(register int i=head[u];i;i=next[i])

}for(register int j=1;j<=dep[v];++j)}}

if(dep[u]-1>=l)

res=max(res,g[dfn[u]]+t.query(1,1,n,dfn[u]+l,dfn[u]+min(r,dep[u]-1)));

return;

}int check(db x)

int main()

dfs(1,0);

db l=0,r=1e6,ans=0;

while(r-l>=eps/10)

else

r=mid;

}printf("%0.3lf\n",ans);

return 0;

}

WC2010 重建計畫

嘟嘟嘟 要不這篇部落格我水一下?思路很顯然,點分治 01分數規劃 單調佇列。但就是難寫。點分治的時候我們把每乙個點到重心這條鏈按深度排序,然後對於每乙個點的鏈就有乙個連續深度的區間可以和這條鏈拼上,因為要找一條權值大於 0 的鏈,那就相當於找這個區間的最大值。然後隨著點深度遞增,這個區間就不斷向左移...

WC2010 重建計畫 長鏈剖分

lg傳送門 又一道長鏈剖分好題。這題寫點分治的人應該比較多吧,但是我太菜了,只會長鏈剖分。如果你還不會長鏈剖分的基本操作,可以看看我的長鏈剖分總結。首先一看求平均值最大,馬上想到套個二分,每次把邊權變為原來的邊權減去二分的答案,看樹上有沒有長度在 l 和 u 之間的正權鏈就好了。於是乎問題就轉變成了...

WC2010 重建計畫 長鏈剖分 點分治

題目描述 有一棵大小為 n 的樹,給定 l,r 要求找到一條長度在 l,r 的路徑,並且路徑上邊權的平均值最大 1 leq n,l,r leq 10 5 前幾天沉迷初賽來寫幾道資料結構恢復一下 能力,坑填完之後可能就要開始啃思維題了qwq。這個題貌似長鏈剖分和點分複雜度都是 o nlog 2n 的,...