Codeforces Global Round 1 F(线段树,dfs序)

题目连接:https://codeforces.com/contest/1110/problem/F
题目大意:
给定一个 n n n 个点的树,满足存在一个 d f s dfs dfs p p p 满足 p [ i ] = i p[i] = i p[i]=i
给出 q q q 组询问 ( v , l , r ) (v,l,r) (v,l,r) 问从 v v v 出发,到标号在 [ l , r ] [l,r] [l,r] 之间的叶子结点的最短路
n , q ≤ 1 0 5 n,q\le10^5 n,q105
复杂度 O ( ( n + q ) l o g n ) O((n+q)logn) O((n+q)logn)


挺蠢得一道题
把询问挂到点上,开个线段树表示当时到每个点的距离
没沿着一条边移动相当于区间加,区间减

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define SZ(x) ((int)(G[x].size()))
#define ll long long
#define fr first
#define se second
int rd()
{
    int sum = 0;char c = getchar();bool flag = true;
    while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
    while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
    if(flag) return sum;
    else return -sum;
}
const ll INF = 2e18;
int n,Q;
int fa[501000];
int linkk[501000],t;
int tmp[501000],tot;
int l[501000],r[501000];
ll ans[501000];
ll dep[501000];
vector< P >G[501000];
vector< pair<int,pair<int,int> > >h[501000];
void insert(int x,int y,int z){G[x].pb(mp(y,z));G[y].pb(mp(x,z));}
inline ll min(ll a,ll b){return a<b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
namespace Tree
{
	ll mn[2001000],det[2001000];
	#define ls (rt<<1)
	#define rs (rt<<1|1)
	void update(int rt){mn[rt] = min(mn[ls],mn[rs]);}
	void build(int rt,int l,int r)
	{
		if(l == r){mn[rt] = dep[tmp[l]];return;}
		int mid = (l+r)>>1;
		build(ls,l,mid);build(rs,mid+1,r);
		update(rt);
	}
	void pushdown(int rt)
	{
		if(det[rt])
		{
			mn[ls] += det[rt];det[ls] += det[rt];
		  	mn[rs] += det[rt];det[rs] += det[rt];
			det[rt] = 0;
		}
	}
	ll query(int rt,int l,int r,int x,int y)
	{
		if(x <= l && r <= y) return mn[rt];
		if(l > y || r < x) return INF;
		pushdown(rt);
		int mid = (l+r)>>1;
		return min(query(ls,l,mid,x,y) , query(rs,mid+1,r,x,y));
	}
	void add(int rt,int l,int r,int x,int y,ll v)
	{
		if(x <= l && r <= y){mn[rt] += v;det[rt] += v;return;}
		int mid = (l+r)>>1;
		pushdown(rt);
		if(mid >= x) add(ls,l,mid,x,y,v);
		if(mid < y) add(rs,mid+1,r,x,y,v);
		update(rt);
	}
}using namespace Tree;
void dfs(int x)
{
	l[x] = tot+1;
	if(SZ(x) == 1) tmp[++tot] = x;
	rep(i,0, SZ(x)-1 ) if(G[x][i].fr != fa[x])
	    dep[G[x][i].fr] = dep[x] + G[x][i].se,dfs(G[x][i].fr);
	r[x] = tot;
}
void work(int x)
{
	for(int i = 0;i < (int)h[x].size();++i) ans[h[x][i].fr] = Tree::query(1,1,tot,h[x][i].se.fr,h[x][i].se.se);
	for(int i = 0;i < (int)G[x].size();++i) if(G[x][i].fr != fa[x])
	{
		int y = G[x][i].fr,L = l[y],R = r[y];
		Tree::add(1,1,tot,L,R,-G[x][i].se);
		if(L > 1) Tree::add(1,1,tot,1,L-1,G[x][i].se);
		if(R < tot) Tree::add(1,1,tot,R+1,tot,G[x][i].se);
		work(y);
		Tree::add(1,1,tot,L,R,G[x][i].se);
		if(L > 1) Tree::add(1,1,tot,1,L-1,-G[x][i].se);
		if(R < tot) Tree::add(1,1,tot,R+1,tot,-G[x][i].se);
	}
}
void init()
{
	n = rd();Q = rd();int v;
	rep(i,2,n) fa[i] = rd(),v = rd(),insert(i,fa[i],v);
	dfs(1);
	Tree::build(1,1,tot);
	rep(i,1,Q)
	{
		int x = rd(),l = rd(),r = rd();
		l = lower_bound(tmp+1,tmp+tot+1,l) - tmp;
		r = upper_bound(tmp+1,tmp+tot+1,r) - tmp - 1;
		h[x].pb(mp( i, mp(l,r) ));
	}
	work(1);
	rep(i,1,Q) printf("%lld\n",ans[i]);
}
int main()
{
	init();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值