最近的葉子

題目來源:CF1110F
【簡要題意】給一棵有邊權的樹,已知各點編號的等於該點的dfs序。求對於每個vi,li,ri,求li到ri中到vi距離最小的葉子結點到vi的距離。

【分析】
暴力樹形dp有70分就果斷寫完去搞T2,結果T2愣是沒有結果。。。。

又是一道方便離線維護的題。和2月24日卡常數那道題頗爲相似。考慮從u到v邊權爲c,顯然有所有v的子樹點距離-c,其餘點距離+c,回溯也也是一個Θ(log2n)\Theta(log_2n)的複雜度。然後處理詢問時用線段樹合併區間最小值
當然也可以通過在線主席樹做,這樣兩道題就更爲相似了。

【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章