1758: [Wc2010]重建计划
Time Limit: 40 Sec Memory Limit: 162 MBSubmit: 2178 Solved: 700
[ Submit][ Status][ Discuss]
Description
Input
第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标号
Output
输出最大平均估值,保留三位小数
Sample Input
4
2 3
1 2 1
1 3 2
1 4 3
2 3
1 2 1
1 3 2
1 4 3
Sample Output
2.500
HINT
20%的数据,N<=5000
30%的数据,N<=100000,原有方案恰好为一条路径
100%的数据,N<=100000,1<=L<=U<=N-1,Vi<=1000000
Source
HOME Back
树分治的题怎么都轻易地这么烦啊qwq。
upd.正解应该是树分治+单调队列 之前一直不知道自己为什么能过 现在有hack数据了 下面的做法正确性的确不能保证 向所有看过我代码的人致歉…
树分治就不用说了,主要是work比较难写。首先我们考虑每层分治换根后,对于根x的所有子节点(删除的不算)进行dfs,求出每个点到根的距离,隶属的子树根节点(x的子节点)和对答案的贡献(注意贡献要longlong)
然后我们考虑如何在统计答案。考虑对于一条到根的路径,如果其本身就在L-U范围内,显然求一次max。否则我们考虑的范围就是不在此子树的结点中长度在max(L-len,1)~min(U-len,maxlen)中。显然我们可以用线段树存储长度为x的最大答案和与最大答案子树不同的最大答案,可以证明只会用到这两个答案。
时间复杂度O(nlognlogS),其中S为子树平均深度。
#include"bits/stdc++.h"
using namespace std;
typedef long long ll;
const int L=3000005;
char _buff[L]; int _pos=-1;
void ReadIn(){fread(_buff,L,sizeof(char),stdin);}
#define fge _buff[++_pos]
inline int read(){
int x=0,f=1; char ch=fge;
while(ch>'9'||ch<'0')
{if(ch=='-')f=-1;ch=fge;}
while(ch<='9'&&ch>='0')
x=x*10+ch-'0',ch=fge;
return x*f;
}
const int N=100005;
struct P{
int v,c;
P(int _=0,int __=0)
{v=_,c=__;}
};
vector<P>e[N];
struct Data{
int len,ffa;ll sval;
Data(int _=0,ll __=0,int ___=0)
{ len=_; sval=__; ffa=___;}
bool operator <(const Data&a)const
{ return sval*(ll)a.len<a.sval*(ll)len;}
Data operator +(const Data&a)const
{ return Data(len+a.len,sval+a.sval,ffa);}
} q[N] ,ans;
bool cmplen(const Data&a,const Data&b)
{ return a.len<b.len;}
int n,size[N],mnr,mxr,c,maxlen;
bool f[N],v[N];
void dfs(int x){
v[x]=true;size[x]=1;int i;
for(i=0;i<e[x].size();i++){
int to=e[x][i].v;
if(!f[to]&&!v[to]){
dfs(to);
size[x]+=size[to];
}
}
v[x]=false;
}
int getweight(int x){
dfs(x);bool move=true;
int m=size[x],i,to,fn;
while(move){
move=false;
for(i=0;i<e[x].size();i++){
to=e[x][i].v;
if(size[to]>size[x])continue;
if(size[to]>m/2&&!f[to]){
x=to;
move=true;
break;
}
}
}
return x;
}
void BuildData(int x,int fa,int d,ll scost){
int i,to,cost;q[++c]=Data(d,scost,fa);
for(v[x]=true,i=0;i<e[x].size();i++){
to=e[x][i].v;cost=e[x][i].c;
if(f[to]||v[to]) continue;
BuildData(to,fa,d+1,scost+cost);
}v[x]=false; maxlen=max(maxlen,d);
}
struct Node{
Data larg,slar;
Node (Data _=Data(N,0,0),Data __=Data(N,0,0))
{ larg=_; slar=__;}
void update(Node a,Node b){
larg=max(a.larg,b.larg);
if(a.larg.ffa!=larg.ffa)slar=max(slar,a.larg);
else if(a.slar.ffa!=larg.ffa)slar=max(slar,a.slar);
if(b.larg.ffa!=larg.ffa)slar=max(slar,b.larg);
else if(b.slar.ffa!=larg.ffa)slar=max(slar,b.slar);
}
} d[4*N];
int pl[N];
void buildpl(int v,int l,int r){
d[v]=Node();int mid=(l+r)>>1;
if(l==r){pl[l]=v;return;}
buildpl(v<<1,l,mid);
buildpl(v<<1|1,mid+1,r);
}
void buildtr(int v,int l,int r){
int mid=(l+r)>>1;
if(l==r){return;}
buildtr(v<<1,l,mid);
buildtr(v<<1|1,mid+1,r);
d[v].update(d[v<<1],d[v<<1|1]);
}
Node ask(int v,int l,int r,Node&dt){
int _l=mnr-dt.larg.len,_r=mxr-dt.larg.len;
if(_r<=0||_l>maxlen)return Node(Data(),Data());
_l=max(_l,l);_r=min(_r,r);
if(_l>_r)return Node(Data(),Data());
Node ret=Node(Data(1,N*1000,dt.larg.ffa),Data(N,0,0));int mid=(l+r)>>1;
if(l>=_l&&r<=_r){ret.update(ret,d[v]);return ret;}
if(_r<=mid)return ask(v<<1,l,mid,dt);
if(_l>mid) return ask(v<<1|1,mid+1,r,dt);
ret.update(ask(v<<1,l,mid,dt),ask(v<<1|1,mid+1,r,dt));
return ret;
}
void work(int x){
c=maxlen=0;v[x]=true;int i,to,cost,j;
fill(q+1,q+size[x],Data());
for(i=0;i<e[x].size();i++){
to=e[x][i].v;cost=e[x][i].c;
if(f[to]||v[to]) continue;
BuildData(to,to,1,cost);
} if(maxlen==0)return;
fill(d+1,d+maxlen*2,Node());
buildpl(1,1,maxlen);
for(i=1;i<=c;i++){
d[pl[q[i].len]].update(d[pl[q[i].len]],Node(q[i],Data(N,0,0)));
} buildtr(1,1,maxlen);
for(i=1;i<=maxlen;i++){
Node th=ask(1,1,maxlen,d[pl[i]]);
if(th.larg.len)
ans=max(ans,th.slar+d[pl[i]].larg);
if(i>=mnr&&i<=mxr)
ans=max(ans,d[pl[i]].larg);
}
}
void TreeConquer(int x){
x=getweight(x);work(x);int i,to;
for(f[x]=true,i=0;i<e[x].size();i++){
to=e[x][i].v;
if(f[to]) continue;
TreeConquer(to);
}
}
int main(){
ReadIn();n=read();int i,u,v,c;
for(mnr=read(),mxr=read(),i=1;i<n;i++){
u=read(),v=read(),c=read();
e[u].push_back(P(v,c));
e[v].push_back(P(u,c));
} ans=Data(N,0,0); TreeConquer(1);
printf("%.3lf\n",(double)ans.sval/ans.len);
return 0;
}