第一行包含一個正整數N,表示X國的城市個數. 第二行包含兩個正整數L和U,表示政策要求的第一期重建方案中修建道路數的上下限 接下來的N-1行描述重建小組的原有方案,每行三個正整數Ai,Bi,Vi分別表示道路(Ai,Bi),其價值爲Vi 其中城市由1..N進行標號php
輸出最大平均估值,保留三位小數ui
N<=100000,1<=L<=U<=N-1,Vi<=1000000 新加數據一組 By leoly,但未重測..2016.9.27spa
如上圖所示
這時咱們發現,每一個點a只會在枚舉到他所在的重鏈的頂端的父親時對效率形成log的影響code
由於:blog
在枚舉a所在的重鏈中的其餘祖先節點時,a所在的子樹都是做爲深度最深的那個而沒有被枚舉(如枚舉b的子樹時,a所在的子樹是最深的,沒有被枚舉深度)隊列
在枚舉更靠上的重鏈內部時,a所在的子樹也是做爲深度最深的那個而沒有被枚舉(如枚舉e的子樹時,a在d這個子樹內,做爲最深的存在,沒有被枚舉深度)ip
在枚舉更靠上的重鏈頂端的父親時,雖然a所在的子樹須要枚舉,但因爲咱們枚舉的是深度,因此由於這個子樹有更深的鏈因此這個效率應該算做那個更深的鏈的效率(如當枚舉d的子樹時,儘管a所在的子樹被枚舉了深度,但這個效率應該被算在cf鏈上)內存
因此這個方法能夠作到nlognget
這個「按子樹最大深度剖分樹鏈,對長鏈連接的子節點不作操做」的技巧被稱做一種長鏈剖分string
因而咱們完美地用$Nlog_2^2N$解決了這個問題
(upd 2018.5.24:不採用線段樹合併,轉而採用基於長鏈剖分的暴力線段樹插入,好像也能夠保證效率)
代碼:
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const LL exp=10000; const LL INF=1e15; struct ss{ int to,next; LL val; }e[200010]; int first[100010],num; struct DT{ LL max; int ch[2]; }data[3000010]; int root[100010],tot; int dep[100010],depst[100010],hw[100010]; LL val[100010]; LL l,r,mid,ans; int n,Low,Top; void build(int ,int ,LL ); bool check(LL ); void dfs_1(int ,int ); void dfs_2(int ); void insert(int ,int ,int&,int ,LL ); LL get_max(int ,int ,int ,int ,int ); LL get_poi_max(int ,int ,int ,int ); void merge(int ,int ,int ,int&); int main() { int i,j,k,o; scanf("%d",&n); scanf("%d%d",&Low,&Top); for(i=1;i<n;i++){ scanf("%d%d%d",&j,&k,&o); build(j,k,o*exp),build(k,j,o*exp); } dfs_1(1,0); l=exp,r=1e10,mid=(l+r)>>1ll; while(l<r-3){ if(check(mid)) l=mid; else r=mid-1; mid=(l+r)>>1ll; } for(mid=r;mid>=l;mid--) if(check(mid)){ printf("%.3lf",mid/10000.0); return 0; } } void build(int f,int t,LL v){ e[++num].next=first[f]; e[num].to=t,e[num].val=v; first[f]=num; } bool check(LL lim){ int i; memset(root,0,sizeof(root)),tot=0; memset(data,0,sizeof(data)),data[0].max=-3*INF; for(i=1;i<=num;i++) e[i].val-=lim; ans=-3e10; dfs_2(1); for(i=1;i<=num;i++) e[i].val+=lim; return ans>=0; } void dfs_1(int now,int fa){ int i; dep[now]=dep[fa]+1; depst[now]=dep[now],hw[now]=-1; for(i=first[now];i;i=e[i].next) if(e[i].to!=fa){ dfs_1(e[i].to,now); if(depst[now]<depst[e[i].to]) depst[now]=depst[e[i].to],hw[now]=i; } } void dfs_2(int now){ int i,j; if(hw[now]!=-1){ val[e[hw[now]].to]=val[now]+e[hw[now]].val; dfs_2(e[hw[now]].to); root[now]=root[e[hw[now]].to]; if(dep[now]+Low<=depst[now]); ans=max(ans,get_max(1,n,root[now],dep[now]+Low,min(depst[now],dep[now]+Top))-val[now]); insert(1,n,root[now],dep[now],val[now]); } else{ insert(1,n,root[now],dep[now],val[now]); return ; } for(i=first[now];i;i=e[i].next) if(dep[e[i].to]>dep[now]&&i!=hw[now]){ val[e[i].to]=val[now]+e[i].val; dfs_2(e[i].to); for(j=dep[e[i].to];j<=depst[e[i].to]&&j<=dep[now]+Top;j++) ans=max(ans,get_poi_max(1,n,root[e[i].to],j)-val[now]+get_max(1,n,root[now],max(dep[now]*2+Low-j,dep[now]+1),min(dep[now]*2+Top-j,depst[now]))-val[now]); merge(1,n,root[e[i].to],root[now]); } } void insert(int l,int r,int&now,int lim,LL x){ if(!now)now=++tot; if(l==r){ data[now].max=x; return ; } int mid=(l+r)>>1; if(lim<=mid) insert(l,mid,data[now].ch[0],lim,x); else insert(mid+1,r,data[now].ch[1],lim,x); data[now].max=max(data[data[now].ch[0]].max,data[data[now].ch[1]].max); } LL get_max(int l,int r,int now,int L,int R){ if(L>R)return data[0].max; if(L<=l&&r<=R) return data[now].max; int mid=(l+r)>>1; LL lm=-INF,rm=-INF; if(L<=mid) lm=get_max(l,mid,data[now].ch[0],L,R); if(R>mid) rm=get_max(mid+1,r,data[now].ch[1],L,R); if(lm>rm) return lm; return rm; } LL get_poi_max(int l,int r,int now,int lim){ if(l==r)return data[now].max; int mid=(l+r)>>1; if(lim<=mid) return get_poi_max(l,mid,data[now].ch[0],lim); else return get_poi_max(mid+1,r,data[now].ch[1],lim); } void merge(int l,int r,int pre,int&now){ if(!now||!pre){ now+=pre; return ; } if(l==r){ data[now].max=max(data[now].max,data[pre].max); return ; } int mid=(l+r)>>1; merge(l,mid,data[pre].ch[0],data[now].ch[0]); merge(mid+1,r,data[pre].ch[1],data[now].ch[1]); data[now].max=max(data[data[now].ch[0]].max,data[data[now].ch[1]].max); }
(bzoj卡到39S......)