列表

详情


NC213806. 路径

描述

给定一棵树,求所有经过点数大于等于二的无向路径中长度第 k 小的。多组询问。

输入描述

第一行两个整数 n,q,分别为点数和询问数。
接下来 n-1 行,每行三个整数 x,y,z,表示 x 到 y 的边长度为 z。
接下来 q 行,每行一个整数 k。保证
对于  的数据,

输出描述

q 行,每行一个整数,为答案。

示例1

输入:

4 6
1 2 3
2 4 4
2 3 3
1
2
3
4
5
6

输出:

3
3
4
6
7
7

原站题解

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

C++(clang++11) 解法, 执行用时: 1929ms, 内存消耗: 15196K, 提交时间: 2021-01-20 21:34:16

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<vector>
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
using namespace std;
typedef long long ll;
typedef double db;
const int N=2e5+5;
const db eps=1e-4;
struct EDGE
{
	int y,z;
};
vector<EDGE> b[N];
int dis[N],dfn[N],rcn[N],td,n,q,i,x,y,z,k,pos;
int cnt[N],Ref[N];
void dfs(int x,int y)
{
	for (auto i:b[x])
	if (i.y!=y)
	{
		dis[i.y]=dis[x]+i.z;
		dfs(i.y,x);
	}
}
void solve(int x,int y)
{
	dfn[x]=++td;
	Ref[td]=x;
	for (auto i:b[x]) if (i.y!=y)
		solve(i.y,x);
	rcn[x]=td;
	int c=dis[x],j,k;
	for (auto i:b[x])
	if (i.y!=y) 
	{
		fo(j,dfn[i.y],rcn[i.y])
		{
			cnt[dis[Ref[j]]-c]++;
			fo(k,rcn[i.y]+1,rcn[x])
				cnt[dis[Ref[j]]+dis[Ref[k]]-c*2]++;
		}
	}
}
int main()
{
	scanf("%d%d",&n,&q);
	fo(i,1,n-1)
	{
		scanf("%d %d %d",&x,&y,&z);
		b[x].push_back({y,z});
		b[y].push_back({x,z});
	} 
	dfs(1,0);
	solve(1,0);
	int mx=2e5;
	fo(i,1,mx)
		cnt[i]+=cnt[i-1];
	fo(i,1,q)
	{
		scanf("%d",&k);
		pos=lower_bound(cnt+1,cnt+1+mx,k)-cnt;
		printf("%d\n",pos);
	}
}

上一题