【AGC007E】Shik and Travel

【AGC007E】Shik and Travel

by AmanoKumiko

Description

给一颗\(N\)个点的树,每个点要么有两个儿子要么是叶子

任意选定一个叶子作为起点,然后要进行\(M-1\)天(\(M\)为叶子个数)的旅行

每次去到一个没经过的叶子,同时在整个过程中每条边的经过次数不超过\(2\)

求最小的最大的每天的旅行的距离

Input

第一行一个数\(N\)

然后\(N-1\)行,第\(i\)行读入\(fa_{i+1},a_{i+1}\)

Output

一行一个整数表示答案

Sample Input

9
1 26166
1 278
2 23731
2 17834
5 4105
5 19470
6 28803
6 3445

Sample Output

52378

Data Constraint

\(2\le N\le 10^5\)\(0\le a_i\le 10^5\)

Solution

先二分答案

容易发现一定会遍历完某一个子树再遍历它的另一个子树

那我们设一个二元组\((u,v)\)表示在某个子树中,存在起点为\(u\),最后到达\(v\)

且中间的所有距离不大于\(mid\)的路径

那么直接做就能得到\(O(n^2)\)的好成绩

我们考虑优化

令合并的起点为\((u1,v1)\),终点为\((u2,v2)\)

把柿子写出来\(dis_{v1}+dis_{u2}-2dis_{root}\le mid\)

那么作为起点时,钦定\(u1\)则需要最小化\(dis_{v1}\)

作为终点同理

这样删除掉不优的状态后就能得到\(O(nlog^2n)\)的复杂度

合并可以用双指针(但我懒所以不想写

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define inf 10000000000000
#define LL long long
#define N 100010

LL le,ri,dis[N],mid;
int n,a[N],ls[N],rs[N];
struct point{int u,v;};

bool cmp1(const point&le,const point&ri){
	return dis[le.u]<dis[ri.u];
}

bool cmp2(const point&le,const point&ri){
	return dis[le.v]<dis[ri.v];
}

vector<point>s1[N],s2[N];

void dfs(int x){
	if(ls[x]){
		dis[ls[x]]=dis[x]+a[ls[x]];dfs(ls[x]);
		dis[rs[x]]=dis[x]+a[rs[x]];dfs(rs[x]);
	}
}

int tp;

void calc(int x){
	tp++;
	if(ls[x]){
		calc(ls[x]);calc(rs[x]);
		if(s2[ls[x]].size()&&s1[rs[x]].size()){
			int lstpos=0;
			F(i,0,s2[ls[x]].size()-1){
				LL Min=inf;int pos=0;
				F(j,0,s1[rs[x]].size()-1){
					if(dis[s1[rs[x]][j].u]<=dis[x]*2+mid-dis[s2[ls[x]][i].v]){
						if(dis[s1[rs[x]][j].v]<Min)Min=dis[s1[rs[x]][j].v],pos=s1[rs[x]][j].v;
					}else break;
				}
				if(pos&&pos!=lstpos)s2[x].push_back((point){s2[ls[x]][i].u,pos}),lstpos=pos;
			}
			lstpos=0;
			F(j,0,s1[rs[x]].size()-1){
				LL Min=inf;int pos=0;
				F(i,0,s2[ls[x]].size()-1){
					if(dis[s2[ls[x]][i].v]<=dis[x]*2+mid-dis[s1[rs[x]][j].u]){
						if(dis[s2[ls[x]][i].u]<Min)Min=dis[s2[ls[x]][i].u],pos=s2[ls[x]][i].u;
					}else break;
				}
				if(pos&&pos!=lstpos)s1[x].push_back((point){pos,s1[rs[x]][j].v}),lstpos=pos;
			}
		}
		if(s2[rs[x]].size()&&s1[ls[x]].size()){
			int lstpos=0;
			F(i,0,s2[rs[x]].size()-1){
				LL Min=inf;int pos=0;
				F(j,0,s1[ls[x]].size()-1){
					if(dis[s1[ls[x]][j].u]<=dis[x]*2+mid-dis[s2[rs[x]][i].v]){
						if(dis[s1[ls[x]][j].v]<Min)Min=dis[s1[ls[x]][j].v],pos=s1[ls[x]][j].v;
					}else break;
				}
				if(pos&&pos!=lstpos)s2[x].push_back((point){s2[rs[x]][i].u,pos}),lstpos=pos;
			}
			lstpos=0;
			F(j,0,s1[ls[x]].size()-1){
				LL Min=inf;int pos=0;
				F(i,0,s2[rs[x]].size()-1){
					if(dis[s2[rs[x]][i].v]<=dis[x]*2+mid-dis[s1[ls[x]][j].u]){
						if(dis[s2[rs[x]][i].u]<Min)Min=dis[s2[rs[x]][i].u],pos=s2[rs[x]][i].u;
					}else break;
				}
				if(pos&&pos!=lstpos)s1[x].push_back((point){pos,s1[ls[x]][j].v}),lstpos=pos;
			}
		}
		sort(s1[x].begin(),s1[x].end(),cmp1);
		sort(s2[x].begin(),s2[x].end(),cmp2);
	}else{
		s1[x].push_back((point){x,x});
		s2[x].push_back((point){x,x});
	}
}

bool check(){
	tp=0;
	F(i,1,n)s1[i].clear(),s2[i].clear();
	calc(1);
	return s1[1].size();
}

int main(){
	freopen("travel.in","r",stdin);
	freopen("travel.out","w",stdout);
	scanf("%d",&n);
	F(i,2,n){
		int fat;
		scanf("%d%d",&fat,&a[i]);
		ls[fat]?rs[fat]=i:ls[fat]=i;
	}
	dfs(1);
	le=-1;ri=10000000001;
	while(le<ri-1)mid=le+ri>>1,check()?ri=mid:le=mid;
	printf("%d",ri);
	return 0;
}
posted @ 2022-02-19 21:54  冰雾  阅读(42)  评论(0编辑  收藏  举报