tmk找三角
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
Sample Output
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;
}