1758: [Wc2010]重建计划

Time Limit: 40 Sec  Memory Limit: 162 MB

Description

 

Input

第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标号

Output

输出最大平均估值,保留三位小数

Sample Input

4
2 3
1 2 1
1 3 2
1 4 3

Sample Output

2.500

HINT

N<=100000,1<=L<=U<=N-1,Vi<=1000000

 

 

 

 

题解

这道题的要求是平均值最大,于是就想到了分数规划

分数规划详见大佬博客:https://www.cnblogs.com/captain1/p/9929128.html

感觉有点像带权二分(雾)

分数规划就是直接二分一下答案,然后把分母乘过来,移一下项,就会发现每一项都会减去一个对应的值

我们只需要把每一个点都赋上一个对应的值来进行验证答案就好啦

 

至于这道题,把|S|乘过来,再移项过去,就可以发现每一条边只需要赋为(长度-1*二分的答案),就可以求它们的最大值

来判断这个最大值是否为0

剩下的就是长链剖分+线段树的板子了

 

有一个小小的疑问,既然我们可以直接求在[L,U]限制下的最大值,为什么不直接求答案呢?

其实我们现在求的最大值只是保证了分子最大,而分母的值是不确定的,所以还是得二分答案。。。

还有一种比二分快10倍的方法,叫做迭代,详见大佬博客:https://blog.csdn.net/C20181220_xiang_m_y/article/details/102211422

 

下面具体讲一下长链剖分

其实长链剖分就是把自己的重儿子设置为拥有最深叶子节点的儿子。(类比重链剖分的重儿子设置的是子树节点最多的儿子)

然后类似于重链剖分

把整棵树的优先重儿子的dfs序求出来

这样一条链上的点就可以在线段树上对应一段连续的区间

 

如何求在[L,U]限制下的边权和最大值?

我们先存一个val[i],表示i节点到根的边权和

类似于dsu on tree的思路

先计算重儿子对答案的贡献(注意判断是否出界)

然后一个个计算轻儿子对答案的贡献

这时,轻儿子已经完成自己子树下面的计算,轻儿子的所有答案都已经合并到了轻儿子的长链上

所以就只用合并当前长链与轻儿子长链的maxval值就好了

总共O(nlogn),加上二分O(nlognlogn)

人生第一道长链剖分

 

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,L,R;
#define N 100005
#define LL long long
const LL INF=0x3f3f3f3f3f3f3f3fll;
const int EXP=10000;
int fir[N],to[2*N],nxt[2*N],cnt;
LL cd[2*N];
void adde(int a,int b,LL c)
{
    to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;cd[cnt]=c;
    to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;cd[cnt]=c;
}
int hei[N],dep[N],fa[N],son[N];
LL val[N];
void dfs1(int u)
{
    hei[u]=dep[u]=dep[fa[u]]+1;
    int v,p;
    for(p=fir[u];p;p=nxt[p]){
        v=to[p];
        if(v!=fa[u]){
            fa[v]=u;val[v]=val[u]+cd[p];
            dfs1(v);
            hei[u]=max(hei[u],hei[v]);
            if(hei[son[u]]<hei[v])
                son[u]=v;
        }
    }
}
int pos[N],dfn,ind[N];
void dfs2(int u)
{
    pos[u]=++dfn;ind[dfn]=u;
    if(son[u]) dfs2(son[u]);
    int v,p;
    for(p=fir[u];p;p=nxt[p]){
        v=to[p];
        if(v!=fa[u]&&v!=son[u])
            dfs2(v);
    }
}
#define lc i<<1
#define rc i<<1|1
struct node{
    int l,r;
    LL x;
}a[N<<2];
void build(int i,int l,int r)
{
    a[i].l=l;a[i].r=r;a[i].x=-INF;
    if(l==r){a[i].x=val[ind[l]];return;}
    int mid=(l+r)>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    a[i].x=max(a[lc].x,a[rc].x);
}
void insert(int i,int x,LL k)
{
    if(x<a[i].l||a[i].r<x) return;
    if(x==a[i].l&&a[i].r==x){
        a[i].x=max(a[i].x,k);
        return;
    }
    insert(lc,x,k);
    insert(rc,x,k);
    a[i].x=max(a[lc].x,a[rc].x);
}
LL query(int i,int l,int r)
{
    if(l>a[i].r||a[i].l>r) return -INF;
    if(l<=a[i].l&&a[i].r<=r)
        return a[i].x;
    return max(query(lc,l,r),query(rc,l,r));
}
LL ans;
void solve(int u)
{
    if(!son[u]) return;
    int l=pos[u],r=pos[u]+hei[u]-dep[u],_L,_R,v,p,d,s;
    solve(son[u]);
    if(l+L<=r)
        ans=max(ans,query(1,l+L,min(r,l+R))-val[u]);
    for(p=fir[u];p;p=nxt[p]){
        v=to[p];
        if(v!=fa[u]&&v!=son[u]){
            solve(v);
            d=v;
            while(d){
                _L=L-(dep[d]-dep[v])-1;
                _R=R-(dep[d]-dep[v])-1;
                if(l+_L<=r)
                    ans=max(ans,query(1,max(l,l+_L),min(r,l+_R))+val[d]-2*val[u]);
                d=son[d];
            }
            d=v;s=son[u];
            while(d){
                insert(1,pos[s],val[d]);
                val[s]=max(val[s],val[d]);
                d=son[d];s=son[s];
            }
        }
    }
}
bool check(LL mid)
{
    for(int i=1;i<=cnt;i++)
        cd[i]-=mid;
    dfn=0;dfs1(1);dfs2(1);build(1,1,n);
    ans=-INF;solve(1);
    for(int i=1;i<=cnt;i++)
        cd[i]+=mid;
    return ans>=0;
}
int main()
{
    int i,u,v,w;
    LL l=0,r=0,mid;
    scanf("%d%d%d",&n,&L,&R);
    for(i=1;i<n;i++){
        scanf("%d%d%d",&u,&v,&w);
        adde(u,v,1ll*EXP*w);
        r=max(r,1ll*w);
    }
    r=1ll*EXP*r;
    while(l<r){
        mid=(l+r)>>1;
        if(check(mid))l=mid+1;
        else r=mid;
    }
    printf("%.3f",1.0*l/EXP);
}