Vijos 1460 拉力赛

描述

车展结束后,游乐园决定举办一次盛大的山道拉力赛,平平和韵韵自然也要来参加大赛。

赛场上共有n个连通的计时点,n-1条赛道(构成了一棵树)。每个计时点的高度都不相同(父结点的高度必然大于子结点),相邻计时点间由赛道相连。由于马力不够,所以韵韵的遥控车只能从高处驶向低处。而且韵韵的车跑完每条赛道都需花费一定的时间。

举办方共拟举办m个赛段的比赛,每次从第u个计时点到第v个计时点,当然其中有不少比赛韵韵的遥控车是不能参加的(因为要上坡)。平平想知道他能参加多少个赛段的比赛,并且想知道他完成这些赛段的总用时。

赛道皆为单向。

格式

输入格式

第一行两个整数n,m。

接下来n-1行每行3个整数a、b、t。

表示韵韵的遥控车可以花t秒从第a个计时点到第b个计时点。

接下来m行每行2个整数u、v,意义如描述所示。

输出格式

第一行输出一个正整数,表示能参加的赛段数。

第二行输出一个正整数,表示总用时。

样例1

样例输入1[复制]

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

样例输出1[复制]

1
2

限制

各个测试点1s

提示

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

题解: 求两个点的LCA,但是有一个现实条件就是,两个点之间一定要有一个点是另一个点的祖先,不然韵韵就无法参加(根据题意),所以判断一下就行。记得答案开long long!!

CODE:

#include <iostream>
#include <cstdio>
#include <cstring>
#define REP(i, s, n) for(int i = s; i <= n; i ++)
#define REP_(i, s, n) for(int i = n; i >= s; i --)
#define MAX_N 10000 + 10

using namespace std;

struct node{
    int v, w, next;
}E[MAX_N << 1];
int head[MAX_N], top = 0;

void add(int u, int v, int w){
    E[++ top].v = v; E[top].w = w; E[top].next = head[u]; head[u] = top;
}

int n, m, deep[MAX_N], sum[MAX_N], go[MAX_N][16];

void DFS(int x, int last){
    for (int i = head[x]; i; i = E[i].next){
        if (E[i].v != last){
            go[E[i].v][0] = x; deep[E[i].v] = deep[x] + 1;
            sum[E[i].v] = sum[x] + E[i].w;
            DFS(E[i].v, x);
        }
    }
}

void prework(){
    REP(k, 1, 15) REP(i, 1, n)
        go[i][k] = go[go[i][k - 1]][k - 1];
}

void goup(int &x, int k){
    REP_(i, 0, 15){
        if ((1 << i) & k) x = go[x][i];
    }
}

int Lca(int x, int y){
    if (deep[x] > deep[y]) goup(x, deep[x] - deep[y]);
    if (deep[y] > deep[x]) goup(y, deep[y] - deep[x]);
    if (x == y) return x;
    REP_(i, 0, 15){
        if (go[x][i] != go[y][i])
            x = go[x][i], y = go[y][i];
    }
    return go[x][0];
}

bool Used[MAX_N];

int main(){
    freopen("1.in", "r", stdin);
    scanf("%d%d", &n, &m);
    memset(Used, 0, sizeof(Used));
    REP(i, 1, n - 1){
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        add(u, v, w); add(v, u, w);
        Used[v] = 1;
    }
    int R;
    REP(i, 1, n) if(!Used[i]) R = i;
    int ret = 0;
    long long res = 0;
    DFS(R, 0); prework();
    REP(i, 1, m){
        int u, v; scanf("%d%d", &u, &v);
        if(Lca(u, v) == u) ret ++, res += (long long)(sum[v] - sum[u]);
    }
    cout << ret << endl << res << endl;
    return 0;
}
时间: 2024-10-09 06:45:58

Vijos 1460 拉力赛的相关文章

Vijos P1460 拉力赛 倍增+LCA/时间戳

因为最近在学LCA,所以一看到这道题就果断码了 倍增+LCA.这道题本质就是判断u是否为v的祖先,AC代码: 1 #include<stdio.h> 2 #include<string.h> 3 #define maxn 233333 4 struct node{ 5 int to,next,w; 6 }; 7 node e[maxn]; 8 int n,m,cnt,pre[maxn],p[maxn][20],len[maxn],count,dis[maxn]; 9 long lo

Vijos上的三道LCA: 1427, 1460, 1710

Vijos上一共有三道标记为LCA的题目:P1427机密信息,P1460拉力赛,P1710Mrw的工资计划. 首先是P1427机密信息.考虑到只需要求一次LCA,数据范围也不大,直接暴力解决,只是分类讨论有点麻烦. 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <queue> 6 #define re

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

Vijos P1785 同学排序【模拟】

同学排序 描述 现有m位同学,第1位同学为1号,第2位同学为2号,依次第m位同学为m号.要求双号的学生站出来,然后余下的重新组合,组合完后,再次让双号的学生站出来,重复n次,问这时有多少同学出来站着? 样例1 样例输入1 1989 5 样例输出1 1926 限制 1s 提示 [数据范围] 1≤n≤10 100≤m≤100000 题目链接:https://vijos.org/p/1785 分析:站出序号为偶数的人,如果总人数为奇数,剩余人数向上取整再折半就好了! 下面给出AC代码: 1 #incl

Vijos 1057 盖房子

二次联通门 : Vijos 1057 盖房子 /* Vijos 1057 盖房子 简单的dp 当前点(i, j)所能构成的最大的正方形的边长 为点(i - 1, j - 1)与(i, j - 1), (i - 1, j)三点中最小的边长构成.. 一遍递推, 一边取最大即可 */ #include <cstdio> #define Max 1009 inline int min (int a, int b) { return a < b ? a : b; } inline int max

Vijos 1193 扫雷 【动态规划】

扫雷 描述 相信大家都玩过扫雷的游戏.那是在一个n*n的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了,"余"任过流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子没有雷,那么它里面的数字表示和他8连通的格子里面雷的数目.现在棋盘是n*2的,第一列里某些格子是雷,而第二列没有雷,如:o 1* 2* 3* 2o 2* 2* 2 ('*'代表有雷,'o'代表无雷)由于第一类的雷有可能有多种方案满足第二列的数的限制,你的任务即根据第二列的信息求第一列雷有多少中摆放方案.

Vijos 1523 贪吃的九头龙 【树形DP】

贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted by JackDavid127 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,

vijos P1448 校门外的树

描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作接下来m行为m个操作 输出格式 对于每个k=2输出一个答案 提示 范围:20%的数据保证,n,m<=10060%的数据保证

Vijos P1061 迎春舞会之三人组舞 DP

题目链接:https://vijos.org/p/1061 n个人选出3*m人,排成m组,每组3人. 站的队形——较矮的2个人站两侧,最高的站中间. 从对称学角度来欣赏,左右两个人的身高越接近,则这一组的“残疾程度”越低. 计算公式为 h=(a-b)^2 (a.b为较矮的2人的身高)现在候选人有n个人,要从他们当中选出3*m个人排舞蹈,要求总体的“残疾程度”最低; input: 第一排为m,n. 第二排n个数字,保证升序排列. 思路:由于和中间高的人无关,但是每次选旁边两个的时候,会由于没有比这