二分答案
然后每个子树维护二元组 (a,b) 表示存在一个进入该子树后,第一天花费为 a ,最后一天花费为 b ,中间天都满足相邻叶子距离小于等于 Mid
直接转移状态数太多,我们发现对于一个 a 只需要最小的 b′ ,一个 b 只需要最小的 a′ ,可以two-pointers合并
那么新的状态数 |S|≤2×min(|S1|,|S2|)
这样状态总数是 O(nlogn)
复杂度就是 O(nlognlogAns)
偷懒懒得归并排序,多一个log
#pragma GCC optimize(2)
#include
#include
#include
#include
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair abcd;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
struct edge{
int u,v,w,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int w,int p){
G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}
#define V G[p].v
vector f[N];
inline bool cmp(abcd x,abcd y){
return x.secondint n;
ll MID,minv[N];
int fat[N];
inline void Solve(vector &ab,vector &cd,vector &f){
if (ab.size()>cd.size()) swap(ab,cd);
sort(ab.begin(),ab.end(),cmp);
sort(cd.begin(),cd.end());
int n1=ab.size(),n2=cd.size(),pnt;
minv[0]=cd[0].second;
for (int i=1;i1],cd[i].second);
pnt=n2-1;
for (int i=0;iwhile (pnt>=0 && ab[i].second+cd[pnt].first>MID) pnt--;
if (pnt>=0)
f.pb(abcd(ab[i].first,minv[pnt]));
}
for (abcd &x:ab) swap(x.first,x.second);
for (abcd &x:cd) swap(x.first,x.second);
sort(ab.begin(),ab.end(),cmp);
sort(cd.begin(),cd.end());
minv[0]=cd[0].second;
for (int i=1;i1],cd[i].second);
pnt=n2-1;
for (int i=0;iwhile (pnt>=0 && ab[i].second+cd[pnt].first>MID) pnt--;
if (pnt>=0)
f.pb(abcd(minv[pnt],ab[i].first));
}
}
inline void dfs(int u){
if (!head[u]) {
f[u].pb(abcd(0,0));
return;
}
int ls=0,rs=0,t1=0,t2=0;
for (int p=head[u];p;p=G[p].next){
dfs(V);
if (!ls) ls=V,t1=G[p].w; else if (!rs) rs=V,t2=G[p].w;
}
vector &ab=f[ls],&cd=f[rs];
for (abcd &x:ab) x.first+=t1,x.second+=t1;
for (abcd &x:cd) x.first+=t2,x.second+=t2;
Solve(ab,cd,f[u]);
}
int main(){
int x,y;
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
read(n);
for (int i=2;i<=n;i++)
read(fat[i]),read(y),add(fat[i],i,y,++inum);
ll L=-1,R=1e10;
while (L+1if (L<1e6 && R>1e6) MID=1e6;
else MID=(L+R)>>1;
for (int i=1;i<=n;i++) f[i].clear();
dfs(1);
//printf("%d\n",f[1].size());
if (!f[1].empty())
R=MID;
else
L=MID;
}
printf("%lld\n",R);
return 0;
}