题解 P4292 【[WC2010]重建计划】
xtx1092515503 · · 题解
这里是某可能假掉的
照着[BJOI2017]树的难题的思路,我们可以很自然地想到这题仍然可以使用单调队列按秩合并,即将分治树中所有点按照深度递增排序,则可选深度区间一定是递减的。因为这一区间是递减的,所以就可以使用单调队列维护。更详细的解释可以在本人的点分治学习笔记找到或者参阅其它神仙的题解。
这里主要是探讨
我们设当前探讨的点是
因为
我们考虑这样一种贪心策略:
当从队尾加入新元素时,只要当前队尾的那条路径与
设队尾元素为
现在我们要来证明,被弹出的
显然,当
但是我们没有考虑到,万一
则显然,此时
如果
那么队首呢?设其为
首先,只要队首已经不合法了(即
然后,我们考虑队首的下一位为
这个格式同队尾的基本一致,故也可以类似地证明。
则我们只要采取bfs解法,就可以在
当然这个证明不很严谨,欢迎来叉。
代码:
#pragma GCC optimize(3)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const ll fni=-1e11;
int n,L,R;
double mx;
int ROOT,SZ,sz[200100],msz[200100];
int dep[200100],mdp[200100],lim;
ll sum[200100],buc[200100];
vector<pair<int,int> >v[200100];
bool vis[200100];
void getsz(int x,int fa){
sz[x]=1;
for(auto i:v[x])if(!vis[i.first]&&i.first!=fa)getsz(i.first,x),sz[x]+=sz[i.first];
}
void getroot(int x,int fa){
sz[x]=1,msz[x]=0;
for(auto i:v[x])if(!vis[i.first]&&i.first!=fa)getroot(i.first,x),sz[x]+=sz[i.first],msz[x]=max(msz[x],sz[i.first]);
msz[x]=max(msz[x],SZ-sz[x]);
if(msz[x]<msz[ROOT])ROOT=x;
}
void getdep(int x,int fa,int fr){
mdp[fr]=max(mdp[fr],dep[x]);
for(auto i:v[x])if(!vis[i.first]&&i.first!=fa)dep[i.first]=dep[x]+1,sum[i.first]=sum[x]+i.second,getdep(i.first,x,fr);
}
bool cmp(pair<int,int>x,pair<int,int>y){
return mdp[x.first]<mdp[y.first];
}
queue<int>q;
deque<int>dq;
void bfsread(int x){
dq.clear();
q.push(x);
int tmp=lim;
while(!q.empty()){
x=q.front(),q.pop();
while(tmp>=0&&tmp+dep[x]>=L){
while(!dq.empty()&&(buc[tmp]+sum[x])*(dq.back()+dep[x])>=(buc[dq.back()]+sum[x])*(tmp+dep[x]))dq.pop_back();
dq.push_back(tmp--);
}
while(!dq.empty()&&dq.front()+dep[x]>R)dq.pop_front();
while(dq.size()>=2&&(buc[dq[0]]+sum[x])*(dq[1]+dep[x])<=(buc[dq[1]]+sum[x])*(dq[0]+dep[x]))dq.pop_front();
if(!dq.empty())mx=max(mx,1.0*(buc[dq.front()]+sum[x])/(dq.front()+dep[x]));
for(auto i:v[x])if(!vis[i.first]&&dep[i.first]>dep[x])q.push(i.first);
}
}
void bfswrite(int x){
q.push(x);
while(!q.empty()){
x=q.front(),q.pop();
buc[dep[x]]=max(buc[dep[x]],sum[x]),lim=max(lim,dep[x]);
for(auto i:v[x])if(!vis[i.first]&&dep[i.first]>dep[x])q.push(i.first);
}
}
void calc(int x){
sum[x]=dep[x]=0;
for(auto i:v[x])if(!vis[i.first])sum[i.first]=i.second,dep[i.first]=1,getdep(i.first,x,i.first);
sort(v[x].begin(),v[x].end(),cmp);
for(auto i:v[x])if(!vis[i.first])mdp[i.first]=0,bfsread(i.first),bfswrite(i.first);
for(int i=1;i<=lim;i++)buc[i]=fni;lim=0;
}
void solve(int x){
calc(x);
getsz(x,0);
vis[x]=true;
for(auto i:v[x])if(!vis[i.first])ROOT=0,SZ=sz[i.first],getroot(i.first,0),solve(ROOT);
}
void read(int &x){
x=0;
char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
}
int main(){
read(n),read(L),read(R);
for(int i=1;i<=n;i++)buc[i]=fni;
for(int i=1,x,y,z;i<n;i++)read(x),read(y),read(z),v[x].push_back(make_pair(y,z)),v[y].push_back(make_pair(x,z));
msz[0]=n+1,SZ=n,getroot(1,0),solve(ROOT);
printf("%.3lf\n",mx);
return 0;
}