傳送門
首先這玩意兒很明顯是分數規劃,二分乙個答案\(mid\),邊權變為\(w_i-mid\),然後看看能不能找到一條路徑長度在\([l,r]\)之間,且邊權總和非負,這個可以轉化為求一條滿足條件的邊權最大的路徑
這個實際上可以用點分做,用單調佇列可以優化到\(o(nlog^2n)\),然而我不知道為什麼寫掛掉了所以這裡就不說了……
我們設\(f_\)表示以\(i\)為根的子樹中,從\(i\)向下走\(j\)步的鏈最長是多少。轉移可以用長鏈剖分優化到均攤\(o(1)\)。查詢答案的話可以用線段樹,這樣的話複雜度就是\(o(nlog^2n)\)
不知道什麼是長鏈剖分的可以看看蒟蒻的筆記
然而不知道為什麼長鏈剖分跑得並沒有點分快
//minamoto
#include#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?eof:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
int read()
const int n=2e5+5,m=n<<2;const double eps=1e-4;
int head[n],next[n],ver[n],edge[n],tot;
inline void add(int u,int v,int e)
int dfn[n],dep[n],son[n],w[n],n,l,r,cnt;
double val[n],f[n],ans,mid;
#define ls (p<<1)
#define rs (p<<1|1)
double s[m];
inline void clear()
double query(int p,int l,int r,int ql,int qr)
void dfs(int u,int fa)
}void dfs1(int u,int fa)
void split(int u,int fa)
for(int i=head[u];i;i=next[i])
for(int j=0;j<=dep[v];++j)
}}inline bool check()
int main()
printf("%.3lf\n",l);return 0;
}
P4292 WC2010 重建計畫
分數規劃和長鏈剖分大體思路大佬們已經講得很清楚了 奈何我太蒟了被有個問題卡了我很久 就是怎麼分配每個子樹對應的線段樹的空間 當我們正在處理x點時 先遞迴處理完它的重兒子也就是y 然後直接讓x繼承y的資料 若y對應的陣列長這樣子 我們發現在y這棵樹中 x為距離1的點就是y距離0的點 x為距離2的點就是...
WC2010 重建計畫
嘟嘟嘟 要不這篇部落格我水一下?思路很顯然,點分治 01分數規劃 單調佇列。但就是難寫。點分治的時候我們把每乙個點到重心這條鏈按深度排序,然後對於每乙個點的鏈就有乙個連續深度的區間可以和這條鏈拼上,因為要找一條權值大於 0 的鏈,那就相當於找這個區間的最大值。然後隨著點深度遞增,這個區間就不斷向左移...
WC2010 重建計畫 題解
給定一棵樹,邊有邊權,要求找到一條長度在 l,r 之間的鏈,使得鏈的總價值和除以鏈長最大 顯然,這個式子的形式讓人想到了01分數規劃。於是根據01分數規劃的套路,先二分乙個答案 考慮如何判斷,現在等於把所有邊都減去了乙個 mid 要看有沒有一條價值大於0的長度介於 l,r 的鏈 是不是感覺點分治呼之...