題面
題意
給出一棵樹,它的節點的標號恰好爲其dfs序,多次詢問,每次詢問給出三個數u,l,r,求點u到標號在中的葉子節點的最近距離。
做法
考慮用線段樹維護點1到各個葉子節點的距離,發現若要維護點1的兒子節點點2到各個葉子節點的距離,只要將點2的子樹中的所有葉子節點的距離減去邊權,其餘葉子節點加上邊權,這樣只要將詢問離線,再維護區間加和區間最小值即可。
代碼
#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N 500100
using namespace std;
ll n,Q,cl,tt,qq,lea[N],id[N],deep[N],in[N],out[N],ans[N];
bool il[N];
struct Node
{
ll ls,rs,mn,sum;
}node[N<<1];
struct Que
{
ll pos,l,r,id;
bool operator < (const Que &u) const
{
return pos<u.pos;
}
}que[N];
vector<ll>to[N],quan[N];
inline void ad(ll u,ll v,ll w)
{
to[u].push_back(v);
quan[u].push_back(w);
}
inline void up(ll now)
{
ll L=node[now].ls,R=node[now].rs;
node[now].mn=min(node[L].mn,node[R].mn)+node[now].sum;
}
void build(ll now,ll l,ll r)
{
if(l==r)
{
node[now].mn=deep[lea[l]];
return;
}
ll mid=((l+r)>>1);
node[now].ls=++tt;
build(tt,l,mid);
node[now].rs=++tt;
build(tt,mid+1,r);
up(now);
}
void add(ll now,ll l,ll r,ll u,ll v,ll w)
{
if(u<=l&&r<=v)
{
node[now].sum+=w;
node[now].mn+=w;
return;
}
ll mid=((l+r)>>1);
if(u<=mid) add(node[now].ls,l,mid,u,v,w);
if(v>mid) add(node[now].rs,mid+1,r,u,v,w);
up(now);
}
ll ask(ll now,ll l,ll r,ll u,ll v)
{
if(u<=l&&r<=v) return node[now].mn;
ll res=INF,mid=((l+r)>>1);
if(u<=mid) res=min(res,ask(node[now].ls,l,mid,u,v));
if(mid<v) res=min(res,ask(node[now].rs,mid+1,r,u,v));
return res+node[now].sum;
}
void dfs(ll now,ll last)
{
ll i,q;
bool flag=0;
in[now]=cl+1;
for(i=0;i<to[now].size();i++)
{
q=to[now][i];
if(q==last) continue;
flag=1;
deep[q]=deep[now]+quan[now][i];
dfs(q,now);
}
if(!flag) lea[++cl]=now,id[now]=cl,il[now]=1;
out[now]=cl;
}
void Dfs(ll now,ll last)
{
ll i,q;
for(;qq<=Q&&que[qq].pos==now;qq++)
{
ans[que[qq].id]=ask(1,1,cl,in[que[qq].l],in[que[qq].r]-(!il[que[qq].r]));
}
for(i=0;i<to[now].size();i++)
{
q=to[now][i];
if(q==last) continue;
add(1,1,cl,in[q],out[q],-quan[now][i]);
if(in[q]>1) add(1,1,cl,1,in[q]-1,quan[now][i]);//cerr<<1<<' '<<in[q]-1<<"+"<<endl;
if(out[q]<cl) add(1,1,cl,out[q]+1,cl,quan[now][i]);//cerr<<out[q]+1<<" "<<cl<<"+"<<endl;
Dfs(q,now);
add(1,1,cl,in[q],out[q],quan[now][i]);
if(in[q]>1) add(1,1,cl,1,in[q]-1,-quan[now][i]);
if(out[q]<cl) add(1,1,cl,out[q]+1,cl,-quan[now][i]);
}
}
int main()
{
ll i,j,p,q;
cin>>n>>Q;
for(i=2;i<=n;i++)
{
scanf("%lld%lld",&p,&q);
ad(i,p,q),ad(p,i,q);
}
for(i=1;i<=Q;i++)
{
scanf("%lld%lld%lld",&que[i].pos,&que[i].l,&que[i].r);
que[i].id=i;
}
sort(que+1,que+Q+1);
dfs(1,-1);
build(tt=1,1,cl);
qq=1;
Dfs(1,-1);
for(i=1;i<=Q;i++) printf("%lld\n",ans[i]);
}