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\n",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\n",L);
    }
    return 0;
}

  

posted @ 2018-10-13 20:07  ~Silent  阅读(184)  评论(0编辑  收藏  举报
Live2D