CF1110F Nearest Leaf 题解
Solution
这个题的性质保证了对于任意的结点,它的子树的结点编号是连续的区间。
考虑离线,将整棵树 DFS 一遍,在这个过程中动态维护当前结点 \(u\) 到所有叶子的距离。
于是问题来了:当我们从 \(u\) DFS 到他的儿子 \(v\) 时,到叶子的距离有什么变化呢?
答案是:以 \(v\) 为根的子树距离 \(-w\),其它结点距离 \(+w\)。由于这两个都是连续区间,所以可以使用线段树维护。
具体细节见代码。
Code
语言标准:C++17。
#include<cstdio>
#include<algorithm>
#include<vector>
#include<tuple>
typedef long long ll;
const int N=5e5;
const ll inf=0x3f3f3f3f3f3f3f3f;
typedef long long ll;
struct Node{
ll v,atag;
};
int n,m;
std::vector<std::pair<int,int>> G[N+10];
ll dis[N+10],a[N+10],ans[N+10];
int cnt,L[N+10],R[N+10],siz[N+10];
std::vector<std::tuple<int,int,int>> q[N+10];
Node t[N*4+10];
// L[u], R[u] 表示以 u 为根的子树中的结点编号的 min 和 max。
void DFS1(int u){
L[u]=++cnt;
siz[u]=1;
for(auto [v,w]:G[u]){
dis[v]=dis[u]+w;
DFS1(v);
siz[u]+=siz[v];
}
R[u]=L[u]+siz[u]-1;
}
// 区间加,区间最小值
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
inline void pushUp(int i){
t[i].v=std::min(t[ls(i)].v,t[rs(i)].v);
}
inline void pushA(int i,ll atag){
t[i].v+=atag;t[i].atag+=atag;
}
inline void pushDown(int i){
if(t[i].atag){
pushA(ls(i),t[i].atag);
pushA(rs(i),t[i].atag);
t[i].atag=0;
}
}
void build(int i,int l,int r){
if(l==r)return t[i].v=a[l],void();
int mid=(l+r)>>1;
build(ls(i),l,mid);
build(rs(i),mid+1,r);
pushUp(i);
}
void modify(int i,int l,int r,int ql,int qr,int x){
if(ql<=l&&r<=qr)return pushA(i,x),void();
int mid=(l+r)>>1;
pushDown(i);
if(ql<=mid)modify(ls(i),l,mid,ql,qr,x);
if(qr>mid) modify(rs(i),mid+1,r,ql,qr,x);
pushUp(i);
}
ll query(int i,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return t[i].v;
int mid=(l+r)>>1;
pushDown(i);
ll res=inf;
if(ql<=mid)res=std::min(res,query(ls(i),l,mid,ql,qr));
if(qr>mid) res=std::min(res,query(rs(i),mid+1,r,ql,qr));
return res;
}
#undef ls
#undef rs
void DFS2(int u){
// 处理所有在 u 结点上的询问
for(auto [l,r,id]:q[u])
ans[id]=query(1,1,n,l,r);
for(auto [v,w]:G[u]){
modify(1,1,n,1,n,w);
modify(1,1,n,L[v],R[v],-2*w);
DFS2(v);
modify(1,1,n,1,n,-w);
modify(1,1,n,L[v],R[v],2*w);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=2;i<=n;i++){
int x,y;scanf("%d%d",&x,&y);
G[x].push_back({i,y});
}
for(auto &x:G)std::sort(x.begin(),x.end());
for(int i=1;i<=m;i++){
int v,l,r;scanf("%d%d%d",&v,&l,&r);
q[v].push_back({l,r,i});
}
DFS1(1);
for(int i=1;i<=n;i++){
if(siz[i]==1)a[i]=dis[i];
else a[i]=inf; // 如果不是叶子结点,直接设为 inf,以忽略它们对答案的影响
}
build(1,1,n);
DFS2(1);
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}
本文来自博客园,作者:registerGen,转载请注明原文链接:https://www.cnblogs.com/registergen/p/cf1110f_solution.html

浙公网安备 33010602011771号