P4292 [WC2010]重建计划(点分治)

· · 个人记录

题意

看见式子显然分数规划,之后变成查询是否存在一条路径权值和大于0,点分治即可。

注意卡常。 code: ``` #include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; const double inf=1e18; const double eps=1e-4; int n,m,L,R,cnt_edge,tot; int head[maxn],a[maxn]; struct edge{int to,nxt;double dis;}e[maxn<<1]; inline int read() { char c=getchar();int res=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar(); return res*f; } inline void add_edge(int u,int v,double w) { e[++cnt_edge].nxt=head[u]; head[u]=cnt_edge; e[cnt_edge].to=v; e[cnt_edge].dis=w; } int root,trsize; int size[maxn],maxs[maxn]; bool vis[maxn]; void getroot(int x,int fa) { size[x]=1;maxs[x]=0; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa||vis[y])continue; getroot(y,x);size[x]+=size[y]; maxs[x]=max(maxs[x],size[y]); } maxs[x]=max(maxs[x],trsize-size[x]); if(maxs[x]<maxs[root])root=x; } void init(int x) { maxs[root=0]=1e9;trsize=size[x]; getroot(x,0);a[++tot]=root;vis[root]=1; for(int i=head[root];i;i=e[i].nxt) { int y=e[i].to; if(vis[y])continue; maxs[root=0]=1e9;trsize=size[y]; getroot(y,x);init(y); } } int now,cnt,last; int dep[maxn],b[maxn],q[maxn]; double ans; double f[maxn],dis[maxn]; bool flag; bool in[maxn]; inline void bfs(int x) { in[b[++cnt]=x]=1; for(int i=last+1;i<=cnt;i++) { int y=b[i]; for(int j=head[y];j;j=e[j].nxt) { int z=e[j].to; if(vis[z]||in[z])continue; dis[z]=dis[y]+e[j].dis;dep[z]=dep[y]+1; in[b[++cnt]=z]=1; } } for(int i=last+1;i<=cnt;i++)in[b[i]]=0; } void solve(int x) { vis[x]=1; f[0]=dis[x]=dep[x]=0;b[cnt=0]=x; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(vis[y])continue; dis[y]=e[i].dis;dep[y]=1; last=cnt;bfs(y); int l=1,r=0; for(int j=min(R,dep[b[cnt]]),k=last+1;j;j--) { while(l<=r&&j+dep[q[l]]<L)l++; while(k<=cnt&&j+dep[b[k]]<L)k++; while(k<=cnt&&j+dep[b[k]]<=R) { while(l<=r&&dis[q[r]]+eps<=dis[b[k]])r--; q[++r]=b[k];k++; } if(l<=r&&f[j]+dis[q[l]]>=-eps)flag=1; } for(int j=last+1;j<=cnt;j++)f[dep[b[j]]]=max(f[dep[b[j]]],dis[b[j]]); } for(int i=0;i<=cnt;i++)f[dep[b[i]]]=-inf; if(flag)return; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(vis[y])continue; solve(a[++now]); if(flag)return; } } inline bool check(double mid) { memset(vis,0,sizeof(vis)); for(int i=1;i<=cnt_edge;i++)e[i].dis-=mid; //ans=-inf; flag=0;solve(a[now=1]); for(int i=1;i<=cnt_edge;i++)e[i].dis+=mid; return flag;//ans>=-eps; } int main() { n=read(),L=read(),R=read(); for(int i=1;i<n;i++) { int u=read(),v=read(),w=read(); add_edge(u,v,w);add_edge(v,u,w); } size[1]=n;init(1); for(int i=1;i<=n;i++)f[i]=-inf; double l=0,r=1e6; for(int i=1;i<=35;i++) { double mid=(l+r)/2.0; if(check(mid))l=mid; else r=mid; } printf("%.3lf",l); return 0; } ```