lca+斐波那契

来源:互联网 发布:mac pro 2016 编辑:程序博客网 时间:2024/06/10 18:01

点击打开链接

Description

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

Input

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

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

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

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

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

Output

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


题解:

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


至于如何求从i到j的每条边呢,求到lca,然后把每条边存下来就好了。
#include <cstdio>#include <set>#include <cstring>#include <iostream>#include <vector>#include <algorithm>using namespace std;const int maxn=100005;int head[maxn];int dis[maxn];int dep[maxn];int fa[maxn],ans[maxn];struct Edge{    int v,w,nxt;}edge[2*maxn];int tol,tot;int n,m;void addedge(int u,int v,int w){    edge[tol].v=v;    edge[tol].w=w;    edge[tol].nxt=head[u];    head[u]=tol++;}void dfs(int u,int d){    dep[u]=d;    for(int i=head[u];i!=-1;i=edge[i].nxt){        int v=edge[i].v;        if(v==fa[u])continue;        fa[v]=u;        dis[v]=edge[i].w;        dfs(v,d+1);    }}bool solve(int u,int v){    tot=0;    memset(ans,0,sizeof(ans));    while(tot<=50&&u!=v){        if(dep[u]<dep[v]){            ans[++tot]=dis[v];            v=fa[v];        }        else{            ans[++tot]=dis[u];            u=fa[u];        }    }    if(tot>=50)return true;    else {        sort(ans+1,ans+1+tot);        for(int i=1;i<=tot-2;++i){            if(ans[i]+ans[i+1]>ans[i+2]){                return true;            }        }    }    return false;}void init(){    tol=0;    memset(head,-1,sizeof(head));    for(int i=0;i<=n;++i)        fa[i]=i;}int main(){    int T;    scanf("%d", &T);    while(T--)    {        scanf("%d", &n);        init();        for(int i = 1; i < n; ++ i)        {            int x, y, l;            scanf("%d%d%d", &x, &y, &l);            addedge(x, y, l);            addedge(y, x, l);        }        dfs(1, 0);        scanf("%d", &m);        for(int i = 0; i < m; ++ i)        {            int x, y;            scanf("%d%d", &x, &y);            puts(solve(x, y) ? "Yes" : "No");        }    }    return 0;}