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
",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)
",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
",l);
// C=1.5;
// solve(tmp);
// printf("%d
",ok);
}