Bzoj1758: [Wc2010]重建计划
#题面
传送门
Sol
题意就是给你一棵树,有边权
求边数在\([L, U]\)内的一条路径,使得边权和除以边数最大,输出这个最大值
二分答案+点分治+单调队列
二分一个答案\(mid\),把所有的边权减去这个\(mid\)就是\(check\)是否有一条边数满足要求的大于等于零的路径
\(bfs\)求出当前每个点到根的\(dis\)和\(deep\),使其递增
记录下每个深度最大的\(dis\),维护这个的递减的单调队列即可
注意常数优化!!!
奉上加了一组数据后的\(TLE\)代码供参考加什么数据咯
然后博主不想改
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(1e5 + 5);
const double EPS(1e-4);
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, L, U, first[_], cnt, mx[_], root, size[_], vis[_], tot;
int mark[_], tmp, deep[_];
double ans, dis[_], t[_];
struct Edge{
int to, w, next;
} edge[_ << 1];
int head, tail, Q[_], deq[_];
IL void Add(RG int u, RG int v, RG int w){
edge[cnt] = (Edge){v, w, first[u]}, first[u] = cnt++;
}
IL void GetRoot(RG int u, RG int ff){
size[u] = 1, mx[u] = 0;
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to;
if(vis[v] || v == ff) continue;
GetRoot(v, u);
size[u] += size[v];
mx[u] = max(mx[u], size[v]);
}
mx[u] = max(mx[u], tot - size[u]);
if(mx[u] < mx[root]) root = u;
}
IL void Bfs(RG double mid, RG int x){
Q[head = tail = 0] = x, mark[x] = 1;
while(head <= tail){
RG int u = Q[head++];
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(vis[v] || mark[v]) continue;
deep[v] = deep[u] + 1, dis[v] = dis[u] + (double)w - mid;
Q[++tail] = v, mark[v] = 1;
}
}
}
IL bool Check(RG double mid, RG int u){
RG int maxd = 0, flg = 0; t[0] = 0;
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to, w = edge[e].w;
if(vis[v]) continue;
dis[v] = (double)w - mid, deep[v] = 1;
Bfs(mid, v);
for(RG int i = 0; i <= tail; ++i) mark[Q[i]] = 0;
RG int he = 0, ta = -1, j = maxd;
for(RG int i = 0; i <= tail; ++i){
RG int x = Q[i];
while(~j && j + deep[x] >= L){
while(he <= ta && t[deq[ta]] < t[j]) --ta;
deq[++ta] = j--;
}
while(he <= ta && deep[x] + deq[he] > U) ++he;
if(he <= ta && dis[x] + t[deq[he]] >= 0){
flg = 1;
break;
}
}
maxd = max(maxd, deep[Q[tail]]);
if(flg) break;
for(RG int i = 0; i <= tail; ++i){
RG int x = Q[i];
t[deep[x]] = max(t[deep[x]], dis[x]);
}
}
for(RG int i = 0; i <= maxd; ++i) t[i] = -1e12;
return flg;
}
IL void Calc(RG int u){
RG double l = ans, r = tmp;
while(r - l > EPS){
RG double mid = (l + r) / 2;
if(Check(mid, u)) l = mid;
else r = mid;
}
ans = l;
}
IL void Solve(RG int u){
vis[u] = 1, Calc(u);
for(RG int e = first[u]; e != -1; e = edge[e].next){
RG int v = edge[e].to;
if(vis[v]) continue;
root = 0, tot = size[v];
if(tot <= L) continue;
GetRoot(v, u), Solve(root);
}
}
int main(RG int argc, RG char* argv[]){
tot = n = Input(), L = Input(), U = Input();
for(RG int i = 0; i <= n; ++i) first[i] = -1, t[i] = -1e12;
for(RG int i = 1; i < n; ++i){
RG int u = Input(), v = Input(), w = Input();
Add(u, v, w), Add(v, u, w), tmp = max(tmp, w);
}
mx[0] = n + 1, GetRoot(1, 0), Solve(root);
printf("%.3lf\n", ans);
return 0;
}