广工2017校赛-F-- tmk找三角

http://gdutcode.sinaapp.com/problem.php?cid=1056&pid=5

Description

有一棵树,树上有只tmk。他在这棵树上生活了很久,对他的构造了如指掌。所以他在树上从来都是走最短路,不会绕路。他还还特别喜欢三角形,所以当他在树上爬来爬去的时候总会在想,如果把刚才爬过的那几根树枝/树干锯下来,能不能从中选三根出来拼成一个三角形呢?

Input

第一行输入一个T,表示有多少组样例。

对于每组数据:第一行包含一个整数 N,表示树上节点的个数(从 1 到 N 标号)。

接下来的 N-1 行包含三个整数 a, b, len,表示有一根长度为 len 的树枝/树干在节点 a 和节点 b 之间。

接下来一行包含一个整数 M,表示询问数。

接下来M行每行两个整数 S, T,表示毛毛虫从 S 爬行到了 T,询问这段路程中的树枝/树干是否能拼成三角形。

Output

对于每组数据,每个询问输出一行,包含"Yes"或“No”,表示是否可以拼成三角形。

Sample Input

2 5 1 2 5 1 3 20 2 4 30 4 5 15 2 3 4 3 5 5 1 4 32 2 3 100 3 5 45 4 5 60 2 1 4 1 3

Sample Output

No Yes No Yes

HINT

对于20%数据 1 ≤ N, M ≤ 1000

对于所有数据 1 ≤ N ≤ 100000, 1 ≤ M ≤ 100000, 1 ≤ len ≤ 1000000000

一道脑洞巨大无比的题目:

假设现在有 n 条线段, 假设 n 条边从小到达排序, 如果这 n 条边中没有三条可以构成
三角形, 那么这 n 条边必须满足关系: A[i] >= A[i-2]+A[i-1], 这里的 A[i]表示第 i 条边的大小。
假设 A[i]尽量取最小 A[i]=A[i-2]+A[i-1], 且 A[1]=A[2]=1, 是不是就是一个斐波那契, 也就
是对于一个 n 条边的集合, 如果不存在三条边能构成一个三角形, 那么最长的边至少为 f[n],
表示斐波那契第 n 项。 而题目中 A[i]<1e9, 也就是只要 n>50, 就必定存在三条边可以构成一
个三角形, 所以我们只需要暴力加入两点路径上的边( 如果大于 50, 直接 Yes) , 然后对这
些边进行排序, 枚举第 i 条边为最长边, 贪心判断 A[i]是否小于 A[i-1]+A[i-2]即可

其实和这道题目是一模一样的:

http://hzwer.com/4896.html

下面的代码为了避免每次查询时都DFS一遍,使用了LCA优化了(最朴素的LCA算法)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100000;
int cnt = 1;
struct edge
{
    int y, val;
    int nxt;
};
edge tree[MAXN * 3];
int head[MAXN];
void addedge(int a, int b, int val)
{
    tree[cnt].y = b, tree[cnt].val = val;
    tree[cnt].nxt = head[a];
    head[a] = cnt++;
}
int dpt[MAXN], fa[MAXN],len[MAXN];
void dfs(int id)
{
    dpt[id] = dpt[fa[id]] + 1;
    int tmp = head[id];
    for (; tmp; tmp = tree[tmp].nxt) {
        if (tree[tmp].y != fa[id]) {
            fa[tree[tmp].y]=id;
            dfs(tree[tmp].y);
        }
        else{
            len[id]=tree[tmp].val;
        }
    }
    return ;
}
int e[MAXN];
int top;
bool check(int a, int b)
{
    top = 0;
    if (dpt[a] < dpt[b]) swap(a, b);
    while (dpt[a]  > dpt[b]) {
        e[++top]=len[a];
        if(top>=50)    return false;
        a=fa[a];
    }
    while(a!=b){
        e[++top]=len[a];
        e[++top]=len[b];
        if(top>=50) return false;
        a=fa[a];
        b=fa[b];
    }
    sort(e+1,e+top+1);
    for(int i=1;i<=top-2;i++){
        if(e[i]+e[i+1]>e[i+2]) return true;
    }
    return false;
}
void init()
{
    cnt=1;
    memset(dpt,0,sizeof(dpt));
    memset(head,0,sizeof(head));
    memset(fa,0,sizeof(fa));
    len[1]=0;
    fa[1]=0;
}
int main()
{
    //freopen("data.in","r",stdin);
    int t;
    int n, a, b, le;
    scanf("%d", &t);
    while (t--) {
        init();
        scanf("%d", &n);
        for (int i = 0; i < n-1; i++) {
            scanf("%d%d%d", &a, &b, &le);
            addedge(a, b, le);
            addedge(b, a, le);
        }
        dfs(1);
        int m;
        scanf("%d", &m);
        for (int i = 0; i < m; i++) {
            scanf("%d%d", &a, &b);
            if (check(a, b))
                printf("Yes\n");
            else
                printf("No\n");
        }
    }
}
时间: 2024-10-16 23:46:15

广工2017校赛-F-- tmk找三角的相关文章

广工2016校赛决赛

重现补的题目. Problem A: Krito的讨伐 思路:不要求一次性杀光一个节点里面的所有怪物. 所以我们可以用一个优先队列.优先去杀那些我们当前可以挑战的,然后注意下处理一个房间可能有多个怪物或者无怪物.当我们杀完第x个房间的怪物时候,那么就把x的下一层的怪物加入队列,如果x的下一层出现了空房间[即房间不存在怪物],那么再把该房间当做新的x,继续加入新x的下一层直到出现了有怪物的房间位置. #define _CRT_SECURE_NO_DEPRECATE #include<iostrea

北邮校赛 F. Gabriel&#39;s Pocket Money(树状数组)

F. Gabriel's Pocket Money 2017- BUPT Collegiate Programming Contest - sync 时间限制 2000 ms 内存限制 65536 KB 题目描述 For centuries, Heaven has required its young angels to live and study among humans in order to become full-fledged angels. This is no different

2015 whu校赛f题big data(dp + 小技巧)

题意是给定五个数n(n <= 100),a,b,l,r 另外有函数序列f(x),其中f(x + 1) = f(x) + a或f(x)+ b,f(0) = 0,问有多少个这样的函数序列f(1)到f(n)使得函数序列的和在l和r之间 解题思路如下: 图片有一处错误,要减去的是a*(n + 1) * n而不是 (b - a)* (n + 1) * n,此外,要注意x/c时向上取整和向下取整的问题. 这道题做做停停一个月了今天终于找时间ac了,有点感人呐 代码如下: #include<cstdio&g

河南工业大学2017校赛题解

问题 A: 饶学妹的比赛 题意: 给你一场比赛每人提交的记录,计算最后的排名 题解: 模拟+排序 代码: 1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #include <stack> 6 #include <cstdio> 7 #include <string> 8 #include <vector> 9 #

xdu2017校赛F

Problem F Dogs of Qwordance Senior Backend R&D Engineers 问题描述 那年夏天,锘爷和杰师傅漫步在知春公园的小道上.他们的妻子.孩子牵 着狗在前面嬉戏,二人笑语盈盈,他们不深究一个小的编程问题,而是对整个 Qwordance (四字舞蹈)公司的发展前景加以描绘.这样的场景,想想就觉得好 美,想想就好向往,想想就好激动.然而,他们的狗觉得这非常的无聊,决定自 己去玩. 杰师傅的狗非常挑剔.它希望找到一块面积为 x 的长方形广场,还要求广 场的长

广州工业大学2016校赛 F 我是好人4 dfs+容斥

Problem F: 我是好人4 Description 众所周知,我是好人!所以不会出太难的题,题意很简单 给你n个数,问你1000000000(含1e9)以内有多少个正整数不是这n个数任意一个的倍数 最后友情提供解题代码(我真是太好人了) void solve(int p[], int n) { int ans = 0; for (int i = 1; i <= 1e9; i++) { int fl = 0; for (int j = 0; j < n; j++) { if (i % p[

西交校赛 F. GZP and Poker

F. GZP and Poker GZP often plays games with his friends.Today they went to a board game.There are n players(including GZP) and all of them have some virtual money on the table. ith of them has ai yuan. Each player can double his virtual wealth any nu

2017 校赛 问题 E: 神奇的序列

[提交][状态][讨论版] 题目描述 Aurora在南宁发现了一个神奇的序列,即对于该序列的任意相邻两数之和都不是三的倍数.现在给你一个长度为n的整数序列,让你判断是否能够通过重新排列序列里的数字使得该序列变成一个神奇的序列. 输入 第一行包含一个数字T(T <= 50), 表示测试数据组数. 每一组测试数据首先给出一个数字n(2 <= n <= 200) 表示序列的长度,接下来n个数ai(1<= ai <= 100) 表示该序列. 输出 每组测试数据输出一行.如果序列能通过

hust校赛 f题 The tree of hust(lis 变形)

题目大意是给出一段数字序列,可以忽略一次一段连续的序列,求忽略后的最长连续上升子序列 思路是dp,用end数组记录以当前元素作为结尾的最长连续上升序列的元素个数,那么不难得到状态转移方程为 dp(i) = max(dp(i - 1),  max( end[k] ) ) + 1 代码如下: #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostr