P4292 WC2010 重建計畫

2022-02-27 20:06:23 字數 1279 閱讀 2404

傳送門

首先這玩意兒很明顯是分數規劃,二分乙個答案\(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 的鏈 是不是感覺點分治呼之...