【JZOJ A组】拉力赛

Description
车展结束后,游乐园决定举办一次盛大的山道拉力赛,平平和韵韵自然也要来参加大赛。
赛场上共有n个连通的计时点,n-1条赛道(构成了一棵树)。每个计时点的高度都不相同(父结点的高度必然大于子结点),相邻计时点间由赛道相连。由于马力不够,所以韵韵的遥控车只能从高处驶向低处。而且韵韵的车跑完每条赛道都需花费一定的时间。
举办方共拟举办m个赛段的比赛,每次从第u个计时点到第v个计时点,当然其中有不少比赛韵韵的遥控车是不能参加的(因为要上坡)。平平想知道他能参加多少个赛段的比赛,并且想知道他完成这些赛段的总用时。

Input
第一行两个整数n,m。
接下来n-1行每行3个整数a、b、t。
表示韵韵的遥控车可以花t秒从第a个计时点到第b个计时点。
接下来m行每行2个整数u、v,意义如描述所示。

Output
第一行输出一个正整数,表示能参加的赛段数。
第二行输出一个正整数,表示总用时。

Sample Input
6 2
1 2 1
2 4 1
2 5 1
5 6 1
1 3 1
2 6
4 5

Sample Output
1
2

Data Constraint

Hint
【数据规模和约定】
第一个计时点的高度是最高的;
u≠v;
对于50%的数据 n≤1000 m≤1000;
对于100%的数据 n≤10000 m≤100000;
答案小于2^64。

思路

这题其实就一个dfs

对图进行一次dfs,记录每个点第一次被访问到的时间戳begin[i]和完成以这个点围根的树的时间戳finish[i]。则u是v的祖先的充要条件是Begin[u]<begin[v]且finish[v]<finish[u]

当然听说LCA也行

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=10077;
int n,m,step,cnt,list[maxn],tot;
ll ans;
struct A
{
	int x,y;
	ll t;
}a[maxn];
struct E
{
	int to,next;
	ll v;
}e[maxn*2];
void add(int u,int v,ll val)
{
	e[++cnt].to=v; e[cnt].next=list[u]; list[u]=cnt; e[cnt].v=val;
}
void dfs(int u,int fa)
{
	a[u].x=step;
	for(int i=list[u]; i; i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa) continue;
		step++; a[v].t+=a[u].t;
		dfs(v,u);
	}
	a[u].y=step;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n-1; i++)
	{
		ll t;
		int x,y;
		scanf("%d%d%lld",&x,&y,&t); add(x,y,t);
		a[y].t=t;
	}
	step=1;
	dfs(1,0);
	for(int i=1; i<=m; i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(a[x].x<=a[y].x&&a[y].x<=a[x].y) tot++,ans+=a[y].t-a[x].t;
	}
	printf("%d\n%lld",tot,ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值