列表

详情


NC14415. 树的距离

描述

wyf非常喜欢树。一棵有根数树上有N个节点,1号点是他的根,每条边都有一个距离,而wyf是个爱问奇怪问题的熊孩子,他想知道对于某个点x,x为根的子树上,所有与x距离大于等于k的点与x的距离之和。

输入描述

第一行一个正整数N

接下来N-1描述这棵树,每行两个数第i行两个数p和D表示树上有一条p到i+1长度为D的边。(p<=i)

下面一行一个正整数Q表示wyf的询问次数。

接下来Q行每行两个正整数x和k。 (1<=N,Q<=2x105,1<=D,K<=106)

输出描述

对于每次询问x,k输出以x为根的子树上,所有与x距离大于等于k的点与x的距离之和。(若不存在这样的点,则输出应为0)

示例1

输入:

3
1 2
1 3
2
1 3
1 2

输出:

3
5

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 456ms, 内存消耗: 33424K, 提交时间: 2019-08-01 21:58:07

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
std::vector<pair<int,int> > G[maxn];
int n,x,q,k;ll dis[maxn],sum[maxn];
int sz[maxn],fa[maxn];
inline void dfs(int u)
{
	sz[u]=1;
	for(auto &it:G[u])
	{
		int v,w;tie(v,w)=it;
		if(v==fa[u])continue;
		fa[v]=u;
		dis[v]=dis[u]+w;
		dfs(v);
		sz[u]+=sz[v];
		sum[u]+=sum[v]+sz[v]*w;
	}
}
inline ll solve(int u)
{
	queue<int>q;
	while(!q.empty())q.pop();
	ll ans=0;
	q.emplace(u);
	while(!q.empty())
	{
		u=q.front();q.pop();
		if(dis[u]-dis[x]>=k)
		{
			ans+=sz[u]*(dis[u]-dis[x])+sum[u];
			continue;
		}
		for(auto &it:G[u])
		{
			int v,w;tie(v,w)=it;
			if(v==fa[u])continue;
			q.emplace(v);
		}
	}
	return ans;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int u,w;scanf("%d%d",&u,&w);
		G[u].emplace_back(i+1,w);
		G[i+1].emplace_back(u,w);
	}
	dfs(1);
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d%d",&x,&k);
		printf("%lld\n",solve(x));
	}
	return 0;
}

上一题