BZOJ1758: [Wc2010]重建計劃
阿新 • • 發佈:2018-12-09
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\n",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)\n",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\n",l); // C=1.5; // solve(tmp); // printf("%d\n",ok); }