[BZOJ1758][WC2010]重建计划(点分治+单调队列)
点分治,对于每个分治中心,考虑求出经过它的符合长度条件的链的最大权值和。
从分治中心dfs下去取出所有链,为了防止两条链属于同一个子树,我们一个子树一个子树地处理。
用s1[i]记录目前分治中心伸下去的链中长度为i的链的最大权值,s2[i]记录新子树中的链的最大权值。
分数规划,考虑合并,枚举长度,由于另一个长度在一个滑动窗口中,所以使用单调队列求解即可。
为了保证复杂度,讲子树按高度排序。注意初始化等问题。
1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 6 using namespace std; 7 8 const int N=200010; 9 const double eps=1e-8,inf=1e9; 10 bool vis[N]; 11 int n,L,R,u,v,w,S,rt,tot,sz[N],f[N],he[N],d[N],q[N]; 12 int cnt,h[N],pre[N],to[N<<1],val[N<<1],nxt[N<<1]; 13 double ans,dis[N],s1[N],s2[N]; 14 vector<int>ve; 15 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; } 16 17 bool cmp(int a,int b){ return he[a]<he[b]; } 18 19 void get(int x,int fa){ 20 sz[x]=1; f[x]=0; 21 For(i,x) if ((k=to[i])!=fa && !vis[k]) 22 get(k,x),f[x]=max(f[x],sz[k]),sz[x]+=sz[k]; 23 f[x]=max(f[x],S-sz[x]); 24 if (f[x]<f[rt]) rt=x; 25 } 26 27 void dfs(int x,int fa){ 28 d[x]=d[fa]+1; he[x]=1; 29 For(i,x) if ((k=to[i])!=fa && !vis[k]) 30 pre[k]=val[i],dfs(k,x),he[x]=max(he[x],he[k]+1); 31 } 32 33 void dfs2(int x,int fa,double mid){ 34 dis[x]=dis[fa]+pre[x]-mid; s2[d[x]]=max(s2[d[x]],dis[x]); 35 For(i,x) if ((k=to[i])!=fa && !vis[k]) dfs2(k,x,mid); 36 } 37 38 bool jud(double mid){ 39 double res=-inf; 40 rep(i,0,tot){ 41 int k=ve[i],st=1,ed=0; dis[rt]=0; 42 rep(j,1,he[k]) s2[j]=-inf; dfs2(k,rt,mid); 43 rep(j,0,he[k]){ 44 if (st<=ed && q[st]>R-j) st++; 45 if (L-j<=he[k]){ 46 while (st<=ed && s1[q[ed]]<s1[L-j]) ed--; 47 q[++ed]=L-j; 48 } 49 if (st<=ed) res=max(res,s1[q[st]]+s2[j]); 50 } 51 rep(j,1,he[k]) s1[j]=max(s1[j],s2[j]); 52 } 53 return res>0; 54 } 55 56 void solve(int x){ 57 vis[x]=1; d[0]=-1; dfs(x,0); dis[x]=0; ve.clear(); 58 For(i,x) if (!vis[k=to[i]]) ve.push_back(k=to[i]); 59 tot=ve.size()-1; 60 if (tot==-1) return; 61 sort(ve.begin(),ve.end(),cmp); 62 int ed=he[ve[tot]]; 63 double L=ans,R=1e6; 64 while (L+eps<R){ 65 double mid=(L+R)/2; 66 rep(i,1,ed) s1[i]=-inf; s1[0]=0; 67 if (jud(mid)) L=mid; else R=mid; 68 } 69 ans=max(ans,L); 70 For(i,x) if (!vis[k=to[i]]) rt=0,S=sz[k],get(k,x),solve(rt); 71 } 72 73 int main(){ 74 freopen("bzoj1758.in","r",stdin); 75 freopen("bzoj1758.out","w",stdout); 76 scanf("%d%d%d",&n,&L,&R); 77 rep(i,2,n) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w); 78 f[0]=n+1; S=n; rt=0; get(1,0); 79 solve(rt); printf("%.3lf\n",ans); 80 return 0; 81 }