題目來源:CF1110F
【簡要題意】給一棵有邊權的樹,已知各點編號的等於該點的dfs序。求對於每個vi,li,ri,求li到ri中到vi距離最小的葉子結點到vi的距離。
【分析】
暴力樹形dp有70分就果斷寫完去搞T2,結果T2愣是沒有結果。。。。
又是一道方便離線維護的題。和2月24日卡常數那道題頗爲相似。考慮從u到v邊權爲c,顯然有所有v的子樹點距離-c,其餘點距離+c,回溯也也是一個的複雜度。然後處理詢問時用線段樹合併區間最小值。
當然也可以通過在線主席樹做,這樣兩道題就更爲相似了。
【code】
去掉O2也可以過,把vector換成鏈式前向星可以更快,std遍歷最好用迭代器。
#pragma GCC optimize(2)
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=5e5+1000;
struct Edge{int v,c;};
vector<Edge>v[maxn];
struct Query{int l,r,id;};
vector<Query>q[maxn];int ans[maxn];
int bg[maxn],ed[maxn],dfs_clock;
int val[maxn];
int n,m;
void dfs(int u){
bg[u]=++dfs_clock;
for(vector<Edge>::iterator it=v[u].begin();it!=v[u].end();it++){
val[(*it).v]=val[u]+(*it).c;
dfs((*it).v);
}
ed[u]=dfs_clock;
if(bg[u]!=ed[u])val[u]=1LL<<60;
}
inline void read(int &x){
x=0;int fl=1;char tmp=getchar();
while(tmp<'0'||tmp>'9'){if(tmp=='-')fl=-fl;tmp=getchar();}
while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
struct Seg{
int l,r,val,tag;
}t[maxn<<2];
inline void update(int x){t[x].val=min(t[x<<1].val,t[x<<1|1].val);}
void build(int x,int l,int r){
t[x].l=l,t[x].r=r;
if(l==r){t[x].val=val[l];return ;}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
update(x);
}
inline void pushdown(int x){
if(!t[x].tag)return ;
t[x<<1].tag+=t[x].tag,t[x<<1|1].tag+=t[x].tag;
t[x<<1].val+=t[x].tag,t[x<<1|1].val+=t[x].tag;
t[x].tag=0;
}
void modify(int x,int l,int r,int val){
if(l<=t[x].l&&t[x].r<=r){
t[x].tag+=val,t[x].val+=val;
return ;
}
pushdown(x);
if(t[x<<1].r>=l)modify(x<<1,l,r,val);
if(t[x<<1|1].l<=r)modify(x<<1|1,l,r,val);
update(x);
}
int query(int x,int l,int r){
if(t[x].l>=l&&t[x].r<=r)return t[x].val;
pushdown(x);
int ret=1LL<<60;
if(t[x<<1].r>=l)ret=min(ret,query(x<<1,l,r));
if(t[x<<1|1].l<=r)ret=min(ret,query(x<<1|1,l,r));
return ret;
}
void solve(int u){
for(vector<Query>::iterator it=q[u].begin();it!=q[u].end();it++){
ans[(*it).id]=query(1,(*it).l,(*it).r);
}
for(vector<Edge>::iterator it=v[u].begin();it!=v[u].end();it++){
int V=(*it).v,c=(*it).c;
modify(1,1,n,c);
modify(1,bg[V],ed[V],-2*c);
solve(V);
modify(1,1,n,-c);
modify(1,bg[V],ed[V],2*c);
}
}
signed main(){
cin>>n>>m;
for(int i=2;i<=n;i++){
int x,y,c;y=i,read(x),read(c);
v[x].push_back((Edge){y,c});
}
dfs(1);
build(1,1,n);
for(int i=1;i<=m;i++){
int v,l,r;read(v),read(l),read(r);
q[v].push_back((Query){l,r,i});
}
solve(1);
for(int i=1;i<=m;i++){
printf("%lld\n",ans[i]);
}
return 0;
}