2017广东工业大学程序设计竞赛决赛-tmk找三角

本文探讨了一种基于树状结构的数据集问题,通过寻找两点间的最短路径并判断这些路径能否构成三角形。利用深度优先搜索和最近公共祖先算法进行高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

tmk找三角

Description

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

Input

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

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

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

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

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

Output

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

Sample Input

251 2 51 3 202 4 304 5 1523 43 551 4 322 3 1003 5 454 5 6021 41 3

Sample Output

NoYesNoYes

HINT


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


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




解题思路:最近公共祖先,所有的边不能组成三角形的最差情况就是斐波那契数列,1 1 2 3 5 8 13 21.......,因为边最长为1e9,所以如果两点之间的边数大于如果大于50条,那么必然能组成三角形,否则的遍历一遍两点之间的边就能判断出能否组成三角形


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <functional>
#include <climits>
 
using namespace std;
 
#define LL long long
const int INF=0x3f3f3f3f;
 
const int N=1e5+10;
int n;
int tot,s[N],e[N<<1],nt[N<<1],l[N<<1];
int f[N],dis[N],dep[N];
 
void addEdge(int u,int v,int w)
{
    e[tot]=v;
    l[tot]=w;
    nt[tot]=s[u];
    s[u]=tot++;
}
 
void dfs(int u,int d)
{
    dep[u]=d;
    for(int i=s[u];~i;i=nt[i])
    {
        int v=e[i];
        if(v==f[u]) continue;
        dis[v]=l[i];
        f[v]=u;
        dfs(v,d+1);
    }
}
 
bool solve(int x, int y)
{
    vector<int>g;
    while(g.size()<50&&x!=y)
    {
        if(dep[x]<dep[y])
        {
            g.push_back(dis[y]);
            y=f[y];
        }
        else
        {
            g.push_back(dis[x]);
            x=f[x];
        }
    }
    if(g.size()>=50) return true;
    sort(g.begin(),g.end());
    int Size=g.size();
    for(int i=0;i+2<Size;i++)
        if(g[i]+g[i+1]>g[i+2]) return true;
    return false;
}
 
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        tot=0;
        memset(s,-1,sizeof s);
        for(int i=1;i<n;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addEdge(u,v,w);
            addEdge(v,u,w);
        }
        dfs(1,0);
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            printf(solve(u,v)?"Yes\n":"No\n");
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值