zoukankan      html  css  js  c++  java
  • 杂题训练之十一

    https://www.luogu.org/problem/P3398

    题目大意:

    询问树上a到b,c到d的两条路径是否相交

    分析:
    我们容易发现,如果相交,记 x=lca(a,b),y=lca(c,d)则必有x在cd路径上或y在ab路径上

    关键就在于如何判断它在路径上:

    【复习】:结合如何判断一个点(x)是否在一条最短路上:起点(S)终点(T)各跑一次最短路(为了处理dis),如果dis(S,x)+dis(x,T)==dis(S,T),那么x就在最短路上

    此题因为是树,两点间只有唯一的最短路,类比处理深度就好

    code:

    #include <cstdio>
    #define DEBUG printf("Passing [%s] in LINE %d.
    ", __FUNCTION__, __LINE__);
    #define MAXN 100005
    using namespace std;
    
    struct edge {
        int v, pre;
    } e[MAXN<<1];
    int N, T, fst[MAXN], dep[MAXN], dp[MAXN][18];
    int vis[MAXN], lg[MAXN];
    
    inline int read()
    {
        register int o = 0;
        register char c = getchar();
        while (c < '0' || c > '9') c = getchar();
        while (c >='0' && c <='9') o = (o<<3)+(o<<1)+(c&15), c = getchar();
        return o;
    }
    inline int abs(int x) { return x > 0 ? x : -x; }
    inline int swap(int &x, int &y) { x ^= y ^= x ^= y; }
    inline int addedge(int a, int b, int k)
    {
        e[k] = (edge){b, fst[a]}, fst[a] = k;
    }
    int build(int k, int d)
    {
        vis[k] = 1, dep[k] = d;
        for (register int o=fst[k]; o; o=e[o].pre)
            if (!vis[e[o].v]) dp[e[o].v][0] = k, build(e[o].v, d+1);
    }
    int prepare(int k)
    {
        vis[k] = 0;
        for (register int i=1; i<=lg[dep[k]]; i++)
            dp[k][i] = dp[dp[k][i-1]][i-1];
        for (register int o=fst[k]; o; o=e[o].pre)
            if (vis[e[o].v]) prepare(e[o].v);
    }
    int init()
    {
        N = read(), T = read();
        for (register int i=1, a, b, c; i<N; i++) {
            a = read(), b = read();
            addedge(a, b, i);
            addedge(b, a, i+N);
        }
        build(1, 0);
        for (register int i=1; i<=N; i++)
            lg[i] = lg[i-1] + ((1<<(lg[i-1]+1)) == i);
        prepare(1);
    }
    int lca(int a, int b)
    {
        if (dep[a] < dep[b]) swap(a, b);
        while (dep[a] > dep[b]) a = dp[a][lg[dep[a]-dep[b]]];
        if (a == b) return a;
        for (register int i=lg[dep[a]]; i>=0; i--) 
            if (dp[a][i] != dp[b][i]) a = dp[a][i], b = dp[b][i];
        return dp[a][0];
    }
    inline int dis(int a, int b)
    {
        register int c = lca(a, b);
        return abs(dep[c]-dep[a]) + abs(dep[c]-dep[b]); 
    }
    int work()
    {
        for (register int a, b, c, d, x, y; T; T--)
        {
            a = read(), b = read(), c = read(), d = read();
            x = lca(a, b), y = lca(c, d);
            if (dis(a, y)+dis(b, y)==dis(a, b) || dis(c, x)+dis(d, x)==dis(c, d)) puts("Y");
            else puts("N");
        }
    }
    int main()
    {
        init();
        work(); 
    }
    
    
  • 相关阅读:
    C# 获取枚举集合的其中两种方式
    UITextField限制字数的方法
    iOS
    iOS
    iOS
    iOS 获取已连接的wifi信息
    AFNetWorking 的简单使用
    CoreData 基本操作方法封装
    在Ios里UIWebView参入js
    AFNetworking教程
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11809159.html
Copyright © 2011-2022 走看看