[CF1110F]CF1110F Nearest Leaf

Description:

给定一棵以1 为根的n个节点有根树

1不是叶子

给定m次询问

形如 v l r

输出以v为起点 终点编号为l - r以内的叶子中 v到叶子最近的距离

注意:如果我们 DFS 这棵树,对于每个点都递增枚举儿子节点,每访问到一个节点就记录其编号,那么得到的序列刚好为 1 到 n。

Hint:

\(n,m \le 5*10^5\)

Solution:

考虑每次走一条边,子树叶子最小值会\(+w_i\),其他叶子会\(-w_i\) (这里没想到)

这样我们可以把询问离线,先把非叶子节点赋为inf

每次在线段树上区间加,区间求min就行了

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const ll mxn=5e5+5;
const ll inf=1e18;
ll n,m,cnt,in[mxn],hd[mxn],sz[mxn];
ll tr[mxn<<2],tag[mxn<<2],dep[mxn],ans[mxn];
struct Q {
	ll l,r,id;
};
vector<Q> q[mxn];

inline ll read() {
	char c=getchar(); ll x=0,f=1;
	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
	return x*f;
}
inline void chkmax(ll &x,ll y) {if(x<y) x=y;}
inline void chkmin(ll &x,ll y) {if(x>y) x=y;}

struct ed {
	ll to,nxt; ll w;
}t[mxn<<1];

void push_down(ll p,ll l,ll r) {
	if(tag[p]) {
		ll mid=(l+r)>>1;
		tag[ls]+=tag[p]; tag[rs]+=tag[p];
		tr[ls]+=tag[p];
		tr[rs]+=tag[p];
		tag[p]=0;
	}
}

inline void add(ll u,ll v,ll w) {
	t[++cnt]=(ed) {v,hd[u],w}; hd[u]=cnt;
}

void update(ll l,ll r,ll ql,ll qr,ll val,ll p) {
	if(ql<=l&&r<=qr) {
		tag[p]+=val;
		tr[p]+=val;
		return ;
	}
	ll mid=(l+r)>>1; push_down(p,l,r);
	if(ql<=mid) update(l,mid,ql,qr,val,ls);
	if(qr>mid) update(mid+1,r,ql,qr,val,rs);
	tr[p]=min(tr[ls],tr[rs]);
}

ll query(ll l,ll r,ll ql,ll qr,ll p) {
	if(ql<=l&&r<=qr) return tr[p];
	ll mid=(l+r)>>1; ll res=inf; push_down(p,l,r);
	if(ql<=mid) chkmin(res,query(l,mid,ql,qr,ls)); 
	if(qr>mid) chkmin(res,query(mid+1,r,ql,qr,rs));
	return res;
}

void mod(ll l,ll r,ll pos,ll val,ll p) {
	if(l==r) {
		tr[p]=val;
		return ;
	}
	ll mid=(l+r)>>1;
	if(pos<=mid) mod(l,mid,pos,val,ls);
	else mod(mid+1,r,pos,val,rs);
	tr[p]=min(tr[ls],tr[rs]);
}

void build(ll l,ll r,ll p) {
	if(l==r) {
		tr[p]=inf;
		return ;
	}
	ll mid=(l+r)>>1;
	build(l,mid,ls);
	build(mid+1,r,rs);
	tr[p]=min(tr[ls],tr[rs]);
}

void dfs(ll u,ll fa) {
	sz[u]=1;
	if(in[u]==1) mod(1,n,u,dep[u],1);
	for(ll i=hd[u];i;i=t[i].nxt) {
		ll v=t[i].to;
		if(v==fa) continue ; 
		dep[v]=dep[u]+t[i].w;
		dfs(v,u); sz[u]+=sz[v];
	}
}

void solve(ll u,ll fa) {
	for(ll i=0;i<q[u].size();++i) {
		Q tp=q[u][i];
		ans[tp.id]=query(1,n,tp.l,tp.r,1);
	}
	for(ll i=hd[u];i;i=t[i].nxt) {
		ll v=t[i].to;
		if(v==fa) continue ;
		update(1,n,1,n,t[i].w,1);
		update(1,n,v,v+sz[v]-1,-2*t[i].w,1);
		solve(v,u);
		update(1,n,1,n,-t[i].w,1);
		update(1,n,v,v+sz[v]-1,2*t[i].w,1);
	}
}

int main()
{
	n=read(); m=read(); ll u,pos,l,r; ll w; build(1,n,1);
	for(ll i=2;i<=n;++i) {
		u=read(); w=read();
		add(u,i,w); add(i,u,w); ++in[u],++in[i];
	}
	for(ll i=1;i<=m;++i) 
		pos=read(),l=read(),r=read(),q[pos].push_back((Q){l,r,i});
	dfs(1,0); solve(1,0);
	for(ll i=1;i<=m;++i) printf("%lld\n",ans[i]);
	return 0;
}

posted @ 2019-03-23 12:11  cloud_9  阅读(201)  评论(0)    收藏  举报