Codeforces Global Round 1 F. Nearest Leaf

链接

http://codeforces.com/contest/1110/problem/F

题解

这题本身不难,但是比赛的时候能不能做到这个题,能不能熟练地想到这些套路并且快速把它写出来就是个问题了
离线,把每个询问挂到对应的点上去
从根节点开始 d f s dfs dfs,每次经过一条边,就根据 d f s dfs dfs序确定影响到的区间,用线段树维护下最小值就行了

代码

//线段树 
#include 
#define maxn 500010 
#define linf (1ll<<60)
#define iinf 0x3f3f3f3f
#define dinf 1e100
using namespace std;
typedef long long ll;
struct segtree
{
	ll l, r, min, add;
	segtree *lch, *rch;
}pool[maxn*4], *root;
ll N, head[maxn], to[maxn], nex[maxn], w[maxn], dist[maxn], etot, lb[maxn], rb[maxn], ndtot, ql[maxn], qr[maxn], Q, ans[maxn];
vector<ll> lis[maxn];
ll read(ll x=0)
{
	ll c, f=1;
	for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
	for(;isdigit(c);c=getchar())x=x*10+c-48;
	return f*x;
}
void adde(ll a, ll b, ll c)
{
	to[++etot]=b;
	w[etot]=c;
	nex[etot]=head[a];
	head[a]=etot;
}
ll dfs(ll pos)
{
	ll i, p, mx=pos;
	lb[pos]=pos;
	for(p=head[pos];p;p=nex[p])
		dist[to[p]]=dist[pos]+w[p], mx=max(mx,dfs(to[p]));
	rb[pos]=mx;
	return mx;
}
void pushdown(segtree *p)
{ 
	p->min+=p->add;
	if(p->lch)p->lch->add+=p->add, p->rch->add+=p->add;
	p->add=0;
}
void pushup(segtree *p)
{
	if(p->lch)pushdown(p->lch), pushdown(p->rch), p->min=min(p->lch->min,p->rch->min);
}
void build(segtree *p, ll l, ll r)
{
	ll mid=l+r>>1;
	p->l=l, p->r=r;
	if(l==r)
	{
		p->min=head[l]?linf:dist[l];
		return;
	}
	build(p->lch=pool+ ++ndtot,l,mid);
	build(p->rch=pool+ ++ndtot,mid+1,r);
	pushup(p);
}
ll segmin(segtree *p, ll l, ll r)
{
	ll mid=p->l+p->r>>1, ans=linf;
	pushdown(p);
	if(l<=p->l and r>=p->r)return p->min;
	if(l<=mid)ans=min(ans,segmin(p->lch,l,r));
	if(r>mid)ans=min(ans,segmin(p->rch,l,r));
	return ans;
}
void segadd(segtree *p, ll l, ll r, ll v)
{
	ll mid=p->l+p->r>>1;
	pushdown(p);
	if(l<=p->l and r>=p->r){p->add+=v;return;}
	if(l<=mid)segadd(p->lch,l,r,v);
	if(r>mid)segadd(p->rch,l,r,v);
	pushup(p);
}
void init()
{
	ll i, p, w, v;
	N=read(), Q=read();
	for(i=2;i<=N;i++)
	{
		p=read(), w=read();
		adde(p,i,w);
	}
	for(i=1;i<=Q;i++)
	{
		v=read(), ql[i]=read(), qr[i]=read();
		lis[v].push_back(i);
	}
	dfs(1);
	build(root=pool+ ++ndtot,1,N);
}
void solve(ll pos)
{
	vector<ll>::iterator it;
	ll p;
	for(it=lis[pos].begin();it!=lis[pos].end();it++)
	{
		ans[*it]=segmin(root,ql[*it],qr[*it]);
	}
	for(p=head[pos];p;p=nex[p])
	{
		segadd(root,lb[to[p]],rb[to[p]],-w[p]);
		if(lb[to[p]]>1)segadd(root,1,lb[to[p]]-1,w[p]);
		if(rb[to[p]]<N)segadd(root,rb[to[p]]+1,N,w[p]);
		solve(to[p]);
		segadd(root,lb[to[p]],rb[to[p]],w[p]);
		if(lb[to[p]]>1)segadd(root,1,lb[to[p]]-1,-w[p]);
		if(rb[to[p]]<N)segadd(root,rb[to[p]]+1,N,-w[p]);
	}
}
void print()
{
	ll i;
	for(i=1;i<=Q;i++)printf("%lld\n",ans[i]);
}
int main()
{
	init();
	solve(1);
	print();
	return 0;
}

你可能感兴趣的:(#,线段树)