1. 程式人生 > >[BZOJ1758][WC2010]重建計劃(點分治+單調佇列)

[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 }