2019.01.26-bzoj1758: [Wc2010]重建计划

题目描述:

算法标签:点分治,二分,分数规划

思路:

考虑二分出答案,于是对于每一个点把他的权值减去二分出的答案的和相加大于0,且长度适宜,则满足。

于是用点分治判断是否存在这样的路径。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define db double
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=2e5+5;const db inf=1e9,eps=1e-4;
bool vis[N],flag;
vector<int> v[N];
db val[N],mid,len[N],mk[N];
int drt[N],nrt,size,maxdep,d[N],mxd,q[N],top,rt;
int n,L,R,head[N],ne[N<<1],to[N<<1],cnt,w[N<<1],sz[N],mx[N];
il int read(){
   int x,f=1;char ch;
   _(!)ch=='-'?f=-1:f;x=ch^48;
   _()x=(x<<1)+(x<<3)+(ch^48);
   return f*x;
}
struct node{
    int tl,hd,n,qx[N];
    il void init(int size){tl=-1;hd=0;n=size;}
    il void ins(int x){
        if(hd<=tl&&qx[tl]<=x)return;
        if(hd<tl&&x>n)return;
        while(len[x]>=len[qx[tl]]&&hd<=tl)tl--;
        qx[++tl]=x;
    }
    il db query(int x){
        
        while(qx[hd]>x&&hd<=tl)hd++;
        if(hd>tl)return -inf;
        return len[qx[hd]];
    }
}Q;
il void insert(int x,int y,int z){
    ne[++cnt]=head[x];head[x]=cnt;
    to[cnt]=y;w[cnt]=z;
}
il void getrt(int x,int fa){
    mx[x]=-1;sz[x]=1;
    for(int i=head[x];i;i=ne[i]){
        if(fa==to[i]||vis[to[i]])continue;
        getrt(to[i],x);sz[x]+=sz[to[i]];
        mx[x]=max(mx[x],sz[to[i]]);
    }
    mx[x]=max(mx[x],size-sz[x]);
    if(mx[x]<mx[rt])rt=x;
}
il void dfs1(int x){
    drt[++nrt]=x;vis[x]=1;
    for(int i=head[x];i;i=ne[i]){
        if(vis[to[i]])continue;
        size=sz[to[i]];rt=0;getrt(to[i],x);
        dfs1(rt);
    }
}
il void dfs(int x,int fa){
    mxd=max(mxd,d[x]);
    for(int i=head[x];i;i=ne[i]){
        if(fa==to[i]||vis[to[i]])continue;
        val[to[i]]=val[x]+(db)w[i]-mid;
        d[to[i]]=d[x]+1;dfs(to[i],x);
    }
}
il void bfs(int s,int from){
    q[top=1]=s;mk[s]=from;
    for(int i=1;i<=top;i++){
        for(int j=head[q[i]];j;j=ne[j]){
            if(vis[to[j]]||mk[to[j]]==from)continue;
            mk[q[++top]=to[j]]=from;
        }
    }
}
il void clear(){
    for(int i=0;i<=maxdep;i++){
        len[i]=-inf;v[i].clear();
    }
}
il void solve(int x){
    vis[x]=1;maxdep=0;
    for(int i=head[x];i;i=ne[i]){
        if(vis[to[i]])continue;
        d[to[i]]=1;mxd=0;
        val[to[i]]=(db)w[i]-mid;
        dfs(to[i],x);
        maxdep=max(maxdep,mxd);
        v[mxd].push_back(to[i]);
    }
    for(int i=1;i<=maxdep;i++){
        for(int j=0;j<v[i].size();j++){
            top=0;bfs(v[i][j],x);Q.init(maxdep);
            for(int k=i;k>=L;k--)Q.ins(k);
            for(int k=1;k<=top;k++){
                if(val[q[k]]>=0&&d[q[k]]<=R&&d[q[k]]>=L){flag=1;clear();return;}
                if(d[q[k]]>R)break;
                if(d[q[k]]<L)Q.ins(L-d[q[k]]);
                if(Q.query(R-d[q[k]])+val[q[k]]>=0){flag=1;clear();return;}
            }
            for(int k=1;k<=top;k++){
                len[d[q[k]]]=max(len[d[q[k]]],val[q[k]]);
            }
        }
    }    
    clear();
}
int main()
{
    n=read();L=read();R=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read(),z=read();
        insert(x,y,z);insert(y,x,z);
    }
    mx[0]=n+1;size=n;getrt(1,0);dfs1(rt);
    for(int i=1;i<=n;i++)len[i]=-inf;
    db l=0,r=1000000,ans=0;
    while(l+eps<=r){
        mid=(l+r)/2.0;flag=0;
        for(int i=1;i<=n;i++)vis[i]=0,mk[i]=0;
        for(int i=1;i<=nrt&&!flag;i++)solve(drt[i]);
        if(flag)l=mid,ans=mid;else r=mid;
    }
    printf("%0.3lf
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jessie-/p/10325604.html