最近的叶子

版权声明:写得不好,随便转载,但请注明出处,感激不尽 https://blog.csdn.net/xyc1719/article/details/88383169

题目来源:CF1110F
【简要题意】给一棵有边权的树,已知各点编号的等于该点的dfs序。求对于每个vi,li,ri,求li到ri中到vi距离最小的叶子结点到vi的距离。

【分析】
暴力树形dp有70分就果断写完去搞T2,结果T2愣是没有结果。。。。

又是一道方便离线维护的题。和2月24日卡常数那道题颇为相似。考虑从u到v边权为c,显然有所有v的子树点距离-c,其余点距离+c,回溯也也是一个 Θ ( l o g 2 n ) \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;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/88383169