zoukankan      html  css  js  c++  java
  • BZOJ 1758: [Wc2010]重建计划

    要求平均值最大,二分平均值,判定是否存在一条合法路径权值为正数,点分治+单调队列

    看上去没有任何问题,然而其实每次点分的时候要按子树深度从小到大排序然后更新答案

    复杂度O(n log ^ 2 n)

    这个东西交上去又T了,然后学习了一下分数规划怎么二分,发现了一点神奇的方法,交上去又T了(可能我自己写炸了)........然后把两种拼一起.......跑得飞起

    这题T了7发......

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define eps 1e-5
    using namespace std;
    int Cnt,root,n,N,L,R,sz[100005],Dep[100005],last[100005],vis[100005],q[100005],F_[100005];
    double ANS,cntkey,ans,G[100005],F[100005];
    struct node{
        int to,next;
        double val;
    }e[200005];
    struct node1{
        int Dep,id;
        double val;
    }E[100005];
    void add(int a,int b,double c){
        e[++Cnt].to=b;
        e[Cnt].next=last[a];
        e[Cnt].val=c;
        last[a]=Cnt;
    }
    void find_root(int x,int fa){
        sz[x]=1,F_[x]=0;
        for (int i=last[x]; i; i=e[i].next){
            int V=e[i].to;
            if (vis[V] || V==fa) continue;
            find_root(V,x);
            sz[x]+=sz[V];
            F_[x]=max(F_[x],sz[V]);
        }
        F_[x]=max(F_[x],N-sz[x]);
        if (F_[x]<F_[root]) root=x;
    }
    void get_maxdis(int x,int fa,int dep,int st){
        Dep[st]=max(Dep[st],dep);
        for (int i=last[x]; i; i=e[i].next){
            int V=e[i].to;
            if (vis[V] || V==fa) continue;
            get_maxdis(V,x,dep+1,st);
        }
    }
    bool cmp(node1 a,node1 b){
        return a.Dep<b.Dep;
    }
    void get_dis(int x,int fa,int dep,double val){
        sz[x]=1;
        F[dep]=max(F[dep],val);
        if (dep>=L && dep<=R) ans=max(ans,F[dep]);
        for (int i=last[x]; i; i=e[i].next){
            int V=e[i].to;
            if (vis[V] || V==fa) continue;
            get_dis(V,x,dep+1,val+e[i].val);
            sz[x]+=sz[V];
        }
    }
    void solve(int x){
        int cnt=0;
        for (int i=last[x]; i; i=e[i].next) {
            int V=e[i].to;
            if (vis[V]) continue;
            Dep[V]=0;
            get_maxdis(V,x,1,V);
            E[++cnt]=(node1){Dep[V],V,e[i].val};
        }
        sort(E+1,E+cnt+1,cmp);
        for (int i=1; i<=E[cnt].Dep; i++) G[i]=-1e9;
        for (int i=1; i<=cnt; i++){
            for (int j=1; j<=E[i].Dep; j++) F[j]=-1e9;
            get_dis(E[i].id,x,1,E[i].val);
            int head=1,tail=0,top=0;
            for (int j=E[i].Dep; j>=1; j--){
                int LL=L-j,RR=R-j;
                while (top+1<LL && top+1<=E[i-1].Dep) top++;
                while (top+1>=LL && top+1<=RR && top+1<=E[i-1].Dep){
                    top++;
                    while (head<=tail && G[top]>G[q[tail]]) tail--;
                    q[++tail]=top;
                }
                while (head<=tail && q[head]<LL) head++;
                if (head<=tail) ans=max(ans,G[q[head]]+F[j]);
                if (head<=tail) ANS=max(ANS,(G[q[head]]+F[j]+cntkey*(j+q[head]))/(j+q[head]));
            }
            for (int j=1; j<=E[i].Dep; j++) G[j]=max(G[j],F[j]);
        }
    }
    void divide(int x){
        vis[x]=1;
        solve(x);
        for (int i=last[x]; i; i=e[i].next){
            int V=e[i].to;
            if (vis[V]) continue;
            root=0; N=sz[V];
            find_root(V,x);
            divide(root);
        }
    }
    double check(double key){
        for (int i=1; i<=n; i++) vis[i]=0;
        for (int i=1; i<=Cnt; i++) e[i].val-=key;
        ans=-1e9,ANS=-1;
        N=n;
        find_root(1,0);
        divide(root);
        for (int i=1; i<=Cnt; i++) e[i].val+=key;
        return ANS;
    }
    double check1(double key){
        for (int i=1; i<=n; i++) vis[i]=0;
        for (int i=1; i<=Cnt; i++) e[i].val-=key;
        ans=-1e9,ANS=-1;
        N=n;
        find_root(1,0);
        divide(root);
        for (int i=1; i<=Cnt; i++) e[i].val+=key;
        return ans>=0;
    }
    int main(){
        scanf("%d%d%d",&n,&L,&R);
        double Max=-1e9,Min=1e9;
        for (int i=1; i<n; i++){
            int x,y;
            double z;
            scanf("%d%d%lf",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
            Max=max(Max,z);
            Min=min(Min,z);
        }
        F_[0]=1e9;
        N=n;
        if (n>1000){
            cntkey=0;
            while (1){
                double Sum=check(cntkey);
                if (abs(Sum-cntkey)<eps) break;
                else cntkey=Sum;
            }
            printf("%.3lf
    ",cntkey);
        }
        else{
            double L=Min,R=Max;
            while (R-L>eps){
                double mid=(L+R)/2;
                if (check1(mid)) L=mid;
                else R=mid;
            }
            printf("%.3lf
    ",L);
        }
        return 0;
    }
    

      

  • 相关阅读:
    第五章 Internet协议
    第四章 地址解析协议
    Learn the shell
    Linux学习前的准备
    第三章 链路层
    第二章 Internet 地址结构
    后台数据导出为Excel
    C#开发客户端、JAVA和tomcat开发服务端
    Java基础
    C++学习笔记--(1)
  • 原文地址:https://www.cnblogs.com/silenty/p/9783966.html
Copyright © 2011-2022 走看看