AT2172 [AGC007E] Shik and Travel
https://www.luogu.com.cn/problem/AT2172
挺妙的一道题
首先可以二分答案
考虑一个最暴力的可行性
d
p
dp
dp
设
f
[
u
]
[
a
]
[
b
]
f[u][a][b]
f[u][a][b]表示以
u
u
u为根的子树,第一个到的叶子结点的深度是
a
a
a,最后一个到的叶子结点深度是
b
b
b是否可行
考虑一个节点 x x x的左右儿子 u , v u,v u,v,把他们的dp值合并
f [ x ] [ a ] [ b ] ∣ = f [ u ] [ a ] [ i ] & f [ v ] [ j ] [ b ] & ( d i s ( i , j ) < = w ) f[x][a][b]|=f[u][a][i]\&f[v][j][b]\&(dis(i,j)<=w) f[x][a][b]∣=f[u][a][i]&f[v][j][b]&(dis(i,j)<=w)
再分析一个
f
[
x
]
[
a
]
[
b
]
f[x][a][b]
f[x][a][b], 对于每个
a
a
a,
b
b
b一定越小越好只用保留一个就行了
对于
a
a
a是单调递增,那么
b
b
b一定是单调递减的
所以用
v
e
c
t
o
r
<
p
a
i
r
<
i
n
t
,
i
n
t
>
>
vector<pair<int, int>>
vector<pair<int,int>>保存下来这个
a
,
b
a,b
a,b
状态根据类似启发式合并可以证明状态数是
n
l
o
n
n
nlonn
nlonn的
直接写即可加上排序可能3个log?
完全能过
code:
#include<bits/stdc++.h>
#define N 200050//😅😅😅😅😅😅
#define ll long long
#define pi pair<ll, ll>
#define mkp make_pair
#define fi first
#define se second
using namespace std;
int ch[N][2], val[N];
vector<pi> a[N];
void dfs(int u, ll X) {//😅😅😅😅
vector<pi> ha, f;
a[u].swap(ha);
int ls = ch[u][0], rs = ch[u][1];
if(!ls && !rs) {
a[u].push_back(mkp(0, 0));
return ;
}
dfs(ls, X), dfs(rs, X);
ll t = X - val[ls] - val[rs];
for(int i = 0, j = -1; i < a[ls].size(); i ++) {
while(j + 1 < a[rs].size() && a[rs][j + 1].fi + a[ls][i].se <= t) j ++;
if(j == -1 || j >= a[rs].size()) continue;
f.push_back(mkp( a[ls][i].fi + val[ls], a[rs][j].se + val[rs]));
}
swap(ls, rs);
for(int i = 0, j = -1; i < a[ls].size(); i ++) {
while(j + 1 < a[rs].size() && a[rs][j + 1].fi + a[ls][i].se <= t) j ++;
if(j == -1 || j >= a[rs].size()) continue;
f.push_back(mkp( a[ls][i].fi + val[ls], a[rs][j].se + val[rs]));
}
sort(f.begin(), f.end());
for(int i = 0; i < f.size(); i ++) {
if(a[u].size() && a[u].back().se <= f[i].se) continue;
a[u].push_back(f[i]);
}
}
int check(ll X) {
dfs(1, X);
return a[1].size();
}
int n;
int main() {
scanf("%d", &n);//😅😅😅😅
ll l = -1, r = 0;
for(int i = 2; i <= n; i ++) {
int fa;
scanf("%d%d", &fa, &val[i]);
r += val[i];
if(ch[fa][0]) ch[fa][1] = i;
else ch[fa][0] = i;
}
while(l + 1 < r) {
ll mid = (l + r) >> 1;
if(check(mid)) r = mid;
else l = mid;
}
printf("%lld", r);//😅😅😅
return 0;
}