感觉仿佛所有统计路径的题都可以把锅甩给点分治???
由于要求平均值最大,我们每二分一个答案ave,就去检查是否存在一条路径满足其新路径长度(d(u,v)-ave)的和大于等于0,并且路径的长度在[L,R]之间,检查的时候技巧很多,可以用单调栈来维护当前各深度边权最大值。
同时,要善于利用时间戳来避免一切memset。并且由于答案是三位小数,因此我们可以控制当r-l<=1e-4时跳出即可。
/************************************************************** Problem: 1758 User: RicardoWang Language: C++ Result: Accepted Time:23284 ms Memory:13488 kb ****************************************************************/ #include<cstdlib> #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; #define maxn 100005 #define oo 999999999 struct edge { int to,d,next; bool ban; }e[maxn*2]; int n,edge_ct,head[maxn],sz[maxn],L,R; void add(int x,int y,int de) { e[++edge_ct]=(edge){y,de,head[x],false}; head[x]=edge_ct; return ; } void _read(int &x) { char ch=getchar(); x=0;while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();}return ; } int MMD; void Init() { _read(n);edge_ct=0; _read(L); _read(R); int x,y,z;MMD=-1; for(int i=1;i<n;i++) { _read(x);_read(y); _read(z);MMD=max(MMD,z); add(x,y,z); add(y,x,z); } return ; } int maxd; int maxl[maxn]; void Get_gc(int now,int fa,int size,int &gc) { bool flag=1;int j; sz[now]=1;maxl[now]=0; for(int id=head[now];id;id=e[id].next) { if(e[id].ban || e[id].to==fa)continue; j=e[id].to;Get_gc(j,now,size,gc); if(sz[j]>(size>>1))flag=false; sz[now]+=sz[j]; maxd=max(maxd,maxl[now]+maxl[j]+1);maxl[now]=max(maxl[now],maxl[j]+1); } if(size-sz[now]>(size>>1))flag=false; if(flag)gc=now; return ; } double ans=-oo; int _time,_MaxD; double dp[maxn],dp1[maxn]; int T[maxn]; void DFS(int now,int fa,int dep,double sum,double ave) { _MaxD=max(_MaxD,dep); sz[now]=1; if(T[dep]<_time || (T[dep]==_time && dp1[dep]<sum))dp1[dep]=sum,T[dep]=_time; for(int id=head[now];id;id=e[id].next) { if(e[id].to==fa || e[id].ban)continue; DFS(e[id].to,now,dep+1,sum-ave+(double)e[id].d,ave);sz[now]+=sz[e[id].to]; } return ; } int qu[maxn],front,rear; bool Calc(int now,double ave) { for(int i=0;i<=R;i++)dp[i]=-oo,T[i]=0; dp[0]=0;_time=0; int w;; for(int id=head[now];id;id=e[id].next) { if(e[id].ban)continue; _time++; _MaxD=0; DFS(e[id].to,now,1,(double)e[id].d-ave,ave); //w=min(R,_MaxD); w=max(0,L-_MaxD); front=rear=1; for(int i=_MaxD;i;i--) { for(;w+i<=R;w++) { while(rear>front && dp[w]>dp[qu[rear-1]])rear--; qu[rear++]=w; } while(rear>front && qu[front]+i<L)front++; if(rear>front && dp[qu[front]]+dp1[i]>=0)return true; } for(int j=1;j<=_MaxD && j<=R;j++)if(T[j]==_time) { dp[j]=max(dp[j],dp1[j]); } } return false; } void Tree_Devide(int now,int size) { int gc; maxd=0; Get_gc(now,0,size,gc); if(maxd<L)return ; double l=ans,r=MMD,mid; while(r-l>1e-4) { mid=(l*9.0+r)/10.0; if(Calc(gc,mid)) { ans=mid; l=mid; } else { r=mid; } } for(int id=head[gc];id;id=e[id].next)if(!e[id].ban) { e[id].ban=e[id+(id%2==0 ? -1:1)].ban=true; Tree_Devide(e[id].to,sz[e[id].to]); } return ; } void work() { Tree_Devide(1,n); printf("%.3lf\n",ans); return; } int main() { //freopen("in.txt","r",stdin); Init(); work(); return 0; }