Shik and Travel
Problem Statement
In the country there are
N
cities numbered
A company in city
The travel must start and end at city
1
. If there are
During the whole travel, all roads of the country must be passed through exactly twice.
The amount that the employee must pay for tolls by him/herself is the maximum total toll incurred in a single day during the travel, except the first day and the last day. The remaining tolls will be covered by the company.
Shik, as an employee of this company, has only one hope for his travel. He hopes that the amount he must pay for tolls by himself will be as small as possible. Please help Shik to design the travel which satisfies his hope.
Constraints
2<N<131,072
1≤ai≤i
for all
i
vi
is an integer
The given tree is a full binary tree
Input
The input is given from Standard Input in the following format:
N
a1 v1
a2 v2
:
aN−1 vN−1
Output
Print an integer denoting the minimum amount Shik must pay by himself for tolls incurred during the travel.
Sample Input 1
7
1 1
1 1
2 1
2 1
3 1
3 1
Sample Output 1
4
There are 4 leaves in the tree formed by the cities (cities 4, 5, 6, and 7), so the travel must be 5 days long. There are 4!=24 possible arrangements of the leaf cities to stay during the travel, but some of them are invalid. For example, (4,5,6,7) and (6,7,5,4) are valid orders, but (5,6,7,4) is invalid because the route passes 4 times through the road connecting city 1 and city 2. The figure below shows the routes of the travel for these arrangements.
For all valid orders, day 3 is the day with the maximum total incurred toll of 4, passing through 4 roads.
Sample Input 2
9
1 2
1 2
3 2
3 2
5 2
5 2
7 2
7 2
Sample Output 2
6
The following figure shows the route of the travel for one possible arrangement of the stayed cities for the solution. Note that the tolls incurred in the first day and the last day are always covered by the company.
Sample Input 3
15
1 2
1 5
3 3
4 3
4 3
6 5
5 4
5 3
6 3
3 2
11 5
11 3
13 2
13 1
Sample Output 3
15
Sample Input 4
3
1 0
1 0
Sample Output 4
0
想到方法却不会证明复杂度系列……
神题一道.jpg
思路:
考虑先二分答案,那么现在问题变成了判定合法性。
只要咱们可以构建出一个合法的,且除了第一条和最后一条路径外,没有一条路径边权超过当前二分答案的方案,即可说明其合法性。
那么,考虑如何证明这样方案的存在性:
由于一条边经过次数不超过2,可以很容易发现这样的事实:一旦你进入了某棵子树,只有走完了里面的所有叶子结点,才可以出去。
那么考虑维护一种二元组,形如
(a,b)u
,代表以当前节点
u
为根节点的子树中,入边的长度为
于是每个节点均可以使用
(a,b)u=(a,i)ch[0]+(j,b)ch[1](i+j<=ans)
注意二元组的
a,b
可以互换。
然而可以发现根节点的方案数将会等于爆搜搜到的方案数。
考虑优化状态数,可以发现对于每个
a
,只会需求最小的一个合法的
那么,分割线下为本蒟蒻未想到的部分……
考虑启发式合并,可以发现
于是状态数变成
O(nlogn)
,复杂度是十分正确的
O(nlognlogv)
。
于是做完了~
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'|| ch>'9')ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
typedef long long ll;
typedef pair<ll,ll> pr;
typedef vector<pr> vec;
#define x first
#define y second
const int N=131100;
int n,fa[N];
vec g[N],f[N];
ll mid,mv[N];
inline bool cmpx(pr a,pr b){return a.x<b.x;}
inline bool cmpy(pr a,pr b){return a.y<b.y;}
inline void work(vec &ls,vec &rs,vec &f)
{
if(ls.size()>rs.size())swap(ls,rs);
int el=ls.size(),er=rs.size();
sort(ls.begin(),ls.end(),cmpy);
sort(rs.begin(),rs.end(),cmpx);
mv[0]=rs[0].y;
for(int i=1;i<er;i++)
mv[i]=min(mv[i-1],rs[i].y);
for(int i=0,j=er-1;i<el;i++)
{
while(j>=0 && ls[i].y+rs[j].x>mid)j--;
if(j>=0)f.push_back(pr(ls[i].x,mv[j]));
}
sort(ls.begin(),ls.end(),cmpx);
sort(rs.begin(),rs.end(),cmpy);
mv[0]=rs[0].x;
for(int i=1;i<er;i++)
mv[i]=min(mv[i-1],rs[i].x);
for(int i=0,j=er-1;i<el;i++)
{
while(j>=0 && ls[i].x+rs[j].y>mid)j--;
if(j>=0)f.push_back(pr(mv[j],ls[i].y));
}
}
inline void dfs(int u)
{
if(!f[u].empty())f[u].clear();
if(g[u].empty())
{
f[u].push_back(pr(0,0));
return;
}
for(int i=0,e=g[u].size();i<e;i++)
dfs(g[u][i].x);
vec &ls=f[g[u][0].x];
for(int i=0,e=ls.size(),c=g[u][0].y;i<e;i++)
ls[i].x+=c,ls[i].y+=c;
vec &rs=f[g[u][1].x];
for(int i=0,e=rs.size(),c=g[u][1].y;i<e;i++)
rs[i].x+=c,rs[i].y+=c;
work(ls,rs,f[u]);
ls.clear();
rs.clear();
}
int main()
{
n=read();
for(int i=2,a;i<=n;i++)
{
fa[i]=read();
g[fa[i]].push_back(pr(i,read()));
}
ll l=0,r=1e10,ans=1e10;
while(l<=r)
{
mid=l+r>>1;
dfs(1);
if(f[1].empty())
l=mid+1;
else
r=mid-1,ans=mid;
}
printf("%lld\n",ans);
return 0;
}