HRBUST2064-分析极端情况+倍增求树上距离

传送门。一道不错的思考题~

建议自己先思考下,看有没有结论~

我们不妨分析下,无法构成三角形的边最多能有多少条。设边从小到大为e[0],e[1],e[2]...,则要满足e[0]+e[1]<=e[2],e[1]+e[2]<=e[3]...。最坏情况就是斐波那契数列。而边权只有1e9,因此只需要求出这个范围内的斐波那契数列能容纳几项。

f[0]=f[1]=1,则f[51]=32951280099大于1e9。所以在边数大于60时,直接输出Yes是正确的。边数<=60时,直接暴力即可,相信大家都会写。

代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 100000 + 5,SZ1 = 20;

int n,m,D;
int dep[N],fa[N][SZ1];int pa[N][2];
vector<pair<int,int> > G[N];

void dbg(){puts("");}
template<typename T, typename... R>void dbg(const T &f, const R &... r) {
    cout << f << " ";
    dbg(r...);
}
template<typename Type>inline void read(Type &xx){
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;
}

void dfs(int u = 1,int ufa = 0,int w = 0){
    dep[u] = dep[ufa] + 1;fa[u][0] = ufa;
    pa[u][0] = ufa;pa[u][1] = w;
    rep(i,1,D) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for(auto x: G[u]){
        int v = x.first;
        if(v == ufa) continue;
        dfs(v,u,x.second);
    }
}

int LCA(int x,int y){
    if(dep[x] < dep[y]) swap(x,y);
    for(int d = dep[x] - dep[y],i = 0;d;d >>= 1,++i) if(d & 1) x = fa[x][i];
    if(x == y) return x;
    dwn(i,D,0) if(fa[x][i] != fa[y][i]) x = fa[x][i],y = fa[y][i];
    return fa[x][0];
}

inline int dis(int x,int y,int l){
    return dep[x] + dep[y] - (dep[l] << 1);
}

int main(int argc, char** argv) {
    while(~scanf("%d",&n)){
        D = log(n) / log(2) + 1;
        rep(i,1,n) G[i].clear();
        re_(i,1,n){
            int x,y,w;read(x);read(y);read(w);
            G[x].push_back({y,w});G[y].push_back({x,w});
        }
        dfs();
        read(m);
        while(m--){
            int x,y;read(x);read(y);
            int lca = LCA(x,y);
            if(dis(x,y,lca) > 60){
                puts("Yes");continue;
            }
            vector<int> edges;
            for(;x != lca;x = pa[x][0]) edges.push_back(pa[x][1]);
            for(;y != lca;y = pa[y][0]) edges.push_back(pa[y][1]);
            sort(edges.begin(),edges.end());
            bool fl = false;
            re_(i,2,edges.size()) if(edges[i] < edges[i-1] + edges[i-2]){
                fl = true;break;
            }
            puts(fl ? "Yes" : "No");
        }
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值