給定一棵樹,邊有邊權,要求找到一條長度在\([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 的,...