1. 程式人生 > >P4292 [WC2010]重建計劃

P4292 [WC2010]重建計劃

!= 計劃 我不知道 upd 一個 ext href 復雜 最長

傳送門

首先這玩意兒很明顯是分數規劃,二分一個答案\(mid\),邊權變為\(w_i-mid\),然後看看能不能找到一條路徑長度在\([L,R]\)之間,且邊權總和非負,這個可以轉化為求一條滿足條件的邊權最大的路徑

這個實際上可以用點分做,用單調隊列可以優化到\(O(nlog^2n)\),然而我不知道為什麽寫掛掉了所以這裏就不說了……

我們設\(f_{i,j}\)表示以\(i\)為根的子樹中,從\(i\)向下走\(j\)步的鏈最長是多少。轉移可以用長鏈剖分優化到均攤\(O(1)\)。查詢答案的話可以用線段樹,這樣的話復雜度就是\(O(nlog^2n)\)

然而不知道為什麽長鏈剖分跑得並沒有點分快

//minamoto
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
int read(){
    int res,f=1;char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=2e5+5,M=N<<2;const double eps=1e-4;
int head[N],Next[N],ver[N],edge[N],tot;
inline void add(int u,int v,int e){ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;}
int dfn[N],dep[N],son[N],w[N],n,L,R,cnt;
double val[N],f[N],ans,mid;
#define ls (p<<1)
#define rs (p<<1|1)
double s[M];
inline void clear(){for(int i=0;i<M;++i)s[i]=-inf;}
void update(int p,int l,int r,int x,double v){
    if(l==r)return (void)(s[p]=max(s[p],v));
    int mid=(l+r)>>1;
    x<=mid?update(ls,l,mid,x,v):update(rs,mid+1,r,x,v);
    s[p]=max(s[ls],s[rs]);
}
double query(int p,int l,int r,int ql,int qr){
    if(ql<=l&&qr>=r)return s[p];
    int mid=(l+r)>>1;double res=-inf;
    if(ql<=mid)res=max(res,query(ls,l,mid,ql,qr));
    if(qr>mid)res=max(res,query(rs,mid+1,r,ql,qr));
    return res;
}
void dfs(int u,int fa){
    for(int i=head[u];i;i=Next[i]){
        int v=ver[i];if(v==fa)continue;dfs(v,u);
        if(dep[v]>=dep[son[u]])son[u]=v,w[u]=edge[i];
        if(dep[v]+1>dep[u])dep[u]=dep[v]+1;
    }
}
void dfs1(int u,int fa){
    dfn[u]=++cnt;if(son[u])dfs1(son[u],u);
    for(int i=head[u];i;i=Next[i])if(ver[i]!=fa&&ver[i]!=son[u])dfs1(ver[i],u);
}
void split(int u,int fa){
    int pu=dfn[u];
    if(son[u])split(son[u],u),val[pu]=val[pu+1]+w[u]-mid;
    update(1,1,n,pu,f[pu]=-val[pu]);
    if(dep[u]>=L){
        double tmp=query(1,1,n,pu+L,pu+min(dep[u],R));
        ans=max(ans,tmp+val[pu]);
    }
    for(int i=head[u];i;i=Next[i]){
        int v=ver[i],pv=dfn[v];if(v==fa||v==son[u])continue;
        split(v,u);
        for(int j=0;j<=dep[v];++j){
            int l=pu+max(0,L-j-1),r=pu+min(dep[u],R-j-1);
            double tmp=query(1,1,n,l,r);
            ans=max(ans,tmp+val[pv]+val[pu]+f[pv+j]+edge[i]-mid);
        }
        for(int j=0;j<=dep[v];++j){
            double tmp=val[pv]+f[pv+j]+edge[i]-mid-val[pu];
            if(tmp>f[pu+j+1])update(1,1,n,pu+j+1,f[pu+j+1]=tmp);
        }
    }
}
inline bool check(){
    clear();
    ans=-inf,split(1,0);return ans>=eps;
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),L=read(),R=read();
    for(int i=1,u,v,e;i<n;++i)u=read(),v=read(),e=read(),add(u,v,e),add(v,u,e);
    dfs(1,0),dfs1(1,0);
    double l=0,r=1e6;
    while(r-l>eps){
        mid=(l+r)/2;
        check()?l=mid:r=mid;
    }
    printf("%.3lf\n",l);return 0;
}

P4292 [WC2010]重建計劃