zoukankan      html  css  js  c++  java
  • BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758

    01分数规划,所以我们对每个重心进行二分。于是问题转化为Σw[e]-mid>=0, 对于一棵子树维护点的dep,dis,并用队列q存下来。令mx[i]表示当前dep为i的最大权值,维护一个单调队列dq,维护当前符合条件的mx,当我们从q的队尾向前扫时,它的dep是递减的,利用这个性质维护单调队列,最后更新一遍mx。具体看代码吧TAT

    代码:

    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<set>
    #include<cmath>
    #define rep(i,l,r) for (int i=l;i<=r;i++)
    #define down(i,l,r) for (int i=l;i>=r;i--)
    #define clr(x,y) memset(x,y,sizeof(x))
    #define maxn 209000
    #define inf int(1e9)
    #define mm 1000000007
    #define esp 1e-6
    using namespace std;
    #define ll long long
    struct data{int obj,pre; double c;
    }e[maxn*2];
    int head[maxn],s[maxn],q[maxn],dq[maxn],dep[maxn],fa[maxn],vis[maxn];
    double ans,lim,dis[maxn],mx[maxn];
    int n,m,tot,sum,mn,rt,L,U;
    int read(){
        int x=0,f=1; char ch=getchar();
        while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
        while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void insert(int x,int y,double z){
        e[++tot].obj=y; e[tot].c=z; e[tot].pre=head[x]; head[x]=tot;
    }
    void dfs(int u,int fa){
        s[u]=1; int mx=0;
        for (int j=head[u];j;j=e[j].pre){
            int v=e[j].obj;
            if (v!=fa&&!vis[v]) {
                dfs(v,u);
                s[u]+=s[v];
                mx=max(mx,s[v]);
            }
        }
        mx=max(mx,sum-mx);
        if (mx<mn) mn=mx,rt=u;
    }
    bool go(int u,double mid){
        int up=0;
        for (int j=head[u];j;j=e[j].pre){
            int v=e[j].obj;  
            if (vis[v]) continue;
            dep[v]=1; dis[v]=e[j].c-mid; fa[v]=u;
            int l=0,r=1; q[1]=v;
            while (l<r){
                int now=q[++l];
                for (int k=head[now];k;k=e[k].pre){
                    int v=e[k].obj;
                    if (v!=fa[now]&&!vis[v]){
                        fa[v]=now; dep[v]=dep[now]+1; dis[v]=dis[now]+e[k].c-mid;
                        q[++r]=v;
                    }
                }
            }
            int tail=r; l=1; r=0; int now=up;
            rep(i,1,tail){
                while (dep[q[i]]+now>=L&&now>=0){
                    while (l<=r&&mx[now]>mx[dq[r]]) r--;
                    dq[++r]=now;
                    now--;
                }
                while (l<=r&&dep[q[i]]+dq[l]>U) l++;
                if (l<=r&&dis[q[i]]+mx[dq[l]]>=0) return 1;
            }
            rep(i,up+1,dep[q[tail]]) mx[i]=-inf;
            rep(i,1,tail) {
                int now=dep[q[i]];
                mx[now]=max(mx[now],dis[q[i]]);
            }
            up=max(up,dep[q[tail]]);
        }
        return 0;
    }
    void jud(int u){
        double l=ans,r=lim;
        while (r-l>=0.0001){
            double mid=(l+r)/2;
            if (go(u,mid)) l=mid;
            else r=mid;
        }
        ans=l;
    }
    void solve(int u){
        mn=inf;
        dfs(u,0);
        u=rt;
        jud(u);
        vis[u]=1;
         
        for (int j=head[u];j;j=e[j].pre){
            int v=e[j].obj;
            if (!vis[v]) {
                sum=s[v];
                if (sum>L) solve(v);
            }
        }
    }
    int main(){
        n=read();
        L=read(); U=read();
        int x,y; double z;
        rep(i,1,n-1){
            x=read(); y=read(); scanf("%lf",&z);
            insert(x,y,z);
            insert(y,x,z);
            lim=max(lim,z);
        }
        sum=n;
        solve(1);
        printf("%.3lf ",ans);
        return 0;
    }

  • 相关阅读:
    集合关系运算 交、差、并集
    字符串 数字 列表 元祖 字典 的不同分类and集合的概念
    我的python之路6(基础练习)
    我的python之路6(整理)
    编写Linux下socket协议TCP和UDP的Client Server程序
    linux添加新用户
    HTML5怎样在网页中使用摄像头功能 时间:2013-04-10 19:56 来源:18素材
    boost 同步定时器
    C++的multiple definition of *** first defined here错误
    TCP与UDP的区别,以及它们各自的定义
  • 原文地址:https://www.cnblogs.com/ctlchild/p/4985607.html
Copyright © 2011-2022 走看看