1. 程式人生 > >BZOJ1758: [Wc2010]重建計劃

BZOJ1758: [Wc2010]重建計劃

BZOJ1758: [Wc2010]重建計劃

https://lydsy.com/JudgeOnline/problem.php?id=1758

分析:

  • 首先\(01\)分數規劃,轉化為求長度在\([L,U]\)的最長路。
  • 點分治,每層求某深度下的最大\(dis\)
  • 這裡有一個操作,按子樹深度最大值從小往大排序,這樣保證之前操作部分的深度是可以列舉的,這個時間不會超過接下來遍歷子樹的時間。
  • 單調佇列優化即可。

程式碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
#define N 100050
#define db(x) cerr<<#x<<" = "<<x<<endl
typedef long long ll;
typedef double f2;
int n,L,U,siz[N],f[N],used[N],tot,Q[N],fa[N],dep[N],a[N],la,root;
f2 C,dis[N],g[N];
int ok,mx[N];
char buf[100000],*p1,*p2;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {
    int x=0,f=1; char s=nc();
    while(s<'0'||s>'9') {if(s=='-') f=-1; s=nc();}
    while(s>='0'&&s<='9') x=(((x<<2)+x)<<1)+s-'0',s=nc();
    return f*x;
}
struct A {
    int to,val;
    A() {}
    A(int x_,int y_) {to=x_, val=y_;}
};
vector<A>v1[N],v2[N];
void get_root(int x,int y) {
    int i,lim=v1[x].size();
    siz[x]=1; f[x]=0;
    for(i=0;i<lim;i++) {
        int t=v1[x][i].to;
        if(t!=y&&!used[t]) {
            get_root(t,x);
            siz[x]+=siz[t];
            f[x]=max(f[x],siz[t]);
        }
    }
    f[x]=max(f[x],tot-siz[x]);
    if(f[x]<f[root]) root=x;
}
void get_dep(int x,int y) {
    int i,lim=v1[x].size();
    mx[x]=1; siz[x]=1;
    for(i=0;i<lim;i++) {
        int t=v1[x][i].to;
        if(t!=y&&!used[t]) {
            get_dep(t,x);
            mx[x]=max(mx[x],mx[t]+1);
            siz[x]+=siz[t];
        }
    }
}
inline bool cmp(const A &x,const A &y) {
    return mx[x.to]<mx[y.to];
}
void get_tree(int x) {
    used[x]=1;
    int i,lim=v1[x].size();
    get_dep(x,0);
    sort(v1[x].begin(),v1[x].end(),cmp);
    for(i=0;i<lim;i++) {
        int t=v1[x][i].to;
        if(!used[t]) {
            root=0;
            tot=siz[t];
            get_root(t,x);
            v2[x].push_back(A(root,0));
            get_tree(root);
        }
    }
}
int nowmx;
int bfs(int s) {
    int l=0,r=0,i;
    Q[r++]=s; dep[s]=1; nowmx=max(nowmx,1);
    while(l<r) {
        int x=Q[l++],lim=v1[x].size();
        for(i=0;i<lim;i++) {
            int t=v1[x][i].to;
            if(t!=fa[x]&&used[t]!=tot) {
                dep[t]=dep[x]+1;
                fa[t]=x;
                dis[t]=dis[x]+v1[x][i].val-C;
                nowmx=max(nowmx,dep[t]);
                Q[r++]=t;
            }
        }
    }
    return r;
}
int q[N];
void solve(int x) {
    int i,lim1=v1[x].size(),lim2=v2[x].size(),j,k;
    nowmx=0;
    used[x]=tot;
    g[0]=0;
    la=0;
    a[++la]=x;
    for(i=0;i<lim1;i++) {
        int t=v1[x][i].to,l=0,r=0;
        if(used[t]==tot) continue;
        fa[t]=x;
        dis[t]=v1[x][i].val-C;
        int lstmx=nowmx;
        int len=bfs(t);
        // db(t);
        // db(nowmx);
        // db(len);
        int m=min(U-1,lstmx);
        for(j=m;j>=(L-1)&&j>=0;j--) {
            while(l<r&&g[j]>=g[q[r-1]]) r--;
            q[r++]=j;
        }
        for(j=0;j<len;j++) a[++la]=Q[j];
        for(j=0;j<len;j++) {
            int p=Q[j];
            //[L-dep[p],U-dep[p]]
            
            if(l==r||L-dep[p]<q[r-1]) {
                for(k=r?(q[r-1]-1):m;k>=0&&k>=L-dep[p];k--) {
                    while(l<r&&g[k]>=g[q[r-1]]) r--;
                    q[r++]=k;
                }
            }
            while(l<r&&q[l]>U-dep[p]) l++;
            if(l<r) {
                if(dis[p]+g[q[l]]>0||abs(dis[p]+g[q[l]])<1e-8) {
                    ok=1;
                }
            }
        }
        for(j=0;j<len;j++) {
            g[dep[Q[j]]]=max(g[dep[Q[j]]],dis[Q[j]]);
        }
        // db(g[1]);
        // db(g[2]);
    }
    for(i=1;i<=la;i++) {
        g[dep[a[i]]]=-1e10;
    }
    if(ok) return ;
    // return ;
    for(i=0;i<lim2;i++) {
        if(siz[v2[x][i].to]>=L)
        solve(v2[x][i].to);
    }
}
void dfs(int x) {
    int i,lim=v2[x].size();
    for(i=0;i<lim;i++) {
        printf("%d -> %d\n",x,v2[x][i].to);
        dfs(v2[x][i].to);
    }
}
int main() {
    n=rd(); L=rd(); U=rd();
    int i,x,y,z,mxx=0,mnn=1<<30;
    for(i=1;i<=n;i++) g[i]=-1e10;
    for(i=1;i<n;i++) {
        x=rd(); y=rd(); z=rd();
        v1[x].push_back(A(y,z));
        v1[y].push_back(A(x,z));
        mxx=max(mxx,z);
        mnn=min(mnn,z);
    }
    f[0]=1<<30;
    tot=n;
    get_root(1,0);
    int tmp=root;
    get_tree(root);
    f2 l=mnn,r=mxx;

    // dfs(tmp); return 0;
    // for(x=1;x<=n;x++) {
    //  int lim=v1[x].size();
    //  for(i=0;i<lim;i++) {
    //      printf("%d -> %d(%d)\n",x,v1[x][i].to,v1[x][i].val);
    //  }
    // }

    tot=2;
    while((r-l)>1e-4) {
        f2 mid=(l+r)/2;
        C=mid; ok=0;
        tot++;
        solve(tmp);
        if(ok) l=mid;
        else r=mid;
    }
    printf("%.3f\n",l);

    // C=1.5;
    // solve(tmp);
    // printf("%d\n",ok);
}