题目大意:
就是给你一个有根树,每个点都有一个编号,编号是它们的 d f s dfs dfs序,现在 q q q次询问,每次询问给你一个点 v v v和一个区间 [ l , r ] [l,r] [l,r],问你,这个区间里面的叶子节点,距离 v v v最近的距离是多少?
每条边是有边权的
n , q ∈ [ 1 , 5 e 5 ] n,q\in[1,5e5] n,q∈[1,5e5]
解题思路:
- 首先我开始想在线处理但是太麻烦了。
- 对于这么多询问的还不强制在线的多半是离线处理!!
- 根据 d f s dfs dfs序我们很容易联想到线段树,唉这里还有个区间查询。
- 那么我们可以把询问按照 u u u进行分类,假设 u u u为根就是线段树里面查询 [ l , r ] [l,r] [l,r]的最小值
- 但是你去枚举根的时候很块超时了
- 那么我们就想到了换根
- 我们看一下每个节点 n o w now now和父亲节点的关系,就是从 f a → n o w fa\rightarrow now fa→now的时候, n o w now now这个子树里面的所有的叶子节点都要减掉 e d g e [ f a → n o w ] . w edge[fa\rightarrow now].w edge[fa→now].w,其他区间加上这个 w w w
- 那么这个问题就愉快的解决了 t i m e : O ( ( n + q ) l o g n ) time:O((n+q)logn) time:O((n+q)logn)
AC code
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
struct node {
int id, l, r;
};
int n, q;
vector<node> G[maxn];
ll ans[maxn];
vector<pair<int,ll> > mp[maxn];
struct Segtree {
ll lazy[maxn << 2], tr[maxn << 2], arr[maxn];
void pushup(int rt) {tr[rt] = min(tr[rt<<1],tr[rt<<1|1]);}
void pushdown(int rt) {
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
tr[rt<<1] += lazy[rt];
tr[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
void build(int rt, int l, int r) {
lazy[rt] = 0;
if(l == r) {
tr[rt] = arr[l];
return;
}
build(Lson);
build(Rson);
pushup(rt);
}
void update(int rt, int l, int r, int posl, int posr,ll val) {
if(posl > posr) return;
if(posl <= l && posr >= r) {
tr[rt] += val;
lazy[rt] += val;
return;
}
pushdown(rt);
if(posl <= mid) update(Lson,posl,posr,val);
if(posr > mid) update(Rson,posl,posr,val);
pushup(rt);
}
ll ask(int rt, int l, int r, int posl, int posr) {
if(posl <= l && posr >= r) return tr[rt];
pushdown(rt);
ll res = LLF;
if(posl <= mid) res = min(res,ask(Lson,posl,posr));
if(posr > mid) res = min(res,ask(Rson,posl,posr));
return res;
}
}sgt;
int L[maxn], R[maxn], tot;
inline void dfs(int u, int fa, ll length) {
sort(mp[u].begin(),mp[u].end());
L[u] = ++ tot;
for(auto it : mp[u]) {
if(it.first == fa) continue;
dfs(it.first,u,length+it.second);
}
R[u] = tot;
if(L[u] == R[u]) sgt.arr[u] = length;//处理出所有叶子节点
else sgt.arr[u] = LLF;
}
inline void dfs2(int u, int fa) {
for(auto it : G[u]) ans[it.id] = sgt.ask(1,1,n,it.l,it.r);
for(auto it : mp[u]) {
if(it.first == fa) continue;
sgt.update(1,1,n,1,L[it.first]-1,it.second); // [1,L-1]
sgt.update(1,1,n,R[it.first]+1,n,it.second); // [R+1,n]
sgt.update(1,1,n,L[it.first],R[it.first],-it.second); // [L,R]
dfs2(it.first,u);
sgt.update(1,1,n,1,L[it.first]-1,-it.second);// 还原
sgt.update(1,1,n,R[it.first]+1,n,-it.second);
sgt.update(1,1,n,L[it.first],R[it.first],it.second);
}
}
int main() {
IOS;
cin >> n >> q;
for(int i = 2; i <= n; ++ i) {
int u;
ll v;
cin >> u >> v;
mp[u].push_back({i,v});
mp[i].push_back({u,v});
}
for(int i = 1; i <= q; ++ i) {
int tag, l, r;
cin >> tag >> l >> r;
G[tag].push_back({i,l,r});
}
dfs(1,0,0);
sgt.build(1,1,n);//建树
dfs2(1,0);//求答案
for(int i = 1; i <= q; ++ i) cout << ans[i] << endl;
}