相交的铁路线

原题:相交的铁路线

算法分析

考虑朴素的算法
t1 = lca(x1,y1), S1 = x1->t1 ∪ t1->y1;
同理可得t2和S2。判断S1∩S2是否为空

假设有交点t且假设经过y1,y2,所以x1->t1->t->y1,x2->t2->t->y2,因为t只有一个父亲,所以t1,t2一定是祖先关系,那么t1或t2一定是交点,假设t1是交点,即t2是t1的祖先,则需要两个判定条件:

  • lca(t1,t2) = t2
  • lca(t1,y2) = t1 或 lca(t1,x2) = t1

程序代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 100050;
struct nod{
    int to, cost;
    nod(int a=0,int b=0){to = a; cost = b;}
};
int dep[maxn], se[maxn*2], no[maxn*2], fir[maxn], st[maxn*2][20], lo[200005];
vector<nod> g[maxn];
int n, m;
int cnt, sum;
int T;
void Init(){
    for(int i = 0; i <= n; i++)
        {
            g[i].clear();
            dep[i] = 0;
        }
    sum = cnt = 0;
}
void mkst(){
    for(int i = 0; i <= cnt; i++) st[i][0] = se[i];
    for(int j = 1; (1<<j) <= cnt; j++)
        for(int i = 1; i <= cnt-(1<<j)+1; i++)
            st[i][j] = min(st[i][j-1], st[i+(1<<(j-1))][j-1]);
}

void dfs(int u, int f, int di){
    dep[u] = di;
    no[++sum] = u;
    int t = sum;
    se[++cnt] = t;
    fir[u] = cnt;
    for(int i = 0; i < g[u].size(); i++)
    {
        if(g[u][i].to == f) continue;
        dfs(g[u][i].to, u, di+g[u][i].cost);
        se[++cnt] = t;
    }
}
int find(int p, int q){
    if(p > q) swap(p, q);
    int j = lo[q-p+1];
    return min(st[p][j],st[q-(1<<j)+1][j]);
}
/*int cal(int x, int y){
    int now = no[find(fir[x], fir[y])];
    return dep[x] + dep[y] -2*dep[now];
}*/
int lca(int a, int b){
    return no[find(fir[a], fir[b])];
}
int main(){
    lo[1] = 0;
    for(int i = 2; i <= 200000; i++) lo[i] = lo[i>>1]+1;
    scanf("%d", &T);
    while(T--){
        Init();
        scanf("%d%d",&n, &m);
        for(int i = 0; i < n-1; i++){
            int u, v;
            scanf("%d%d",&u, &v);
            g[u].push_back({v,1});
            g[v].push_back({u,1});
        }
        dfs(1,0,0);mkst();
        while(m--){
            int x1,x2,y1,y2;
            bool fg = false;
            scanf("%d%d%d%d",&x1, &y1, &x2, &y2);
            int t1 = lca(x1,y1);
            int t2 = lca(x2,y2);
            if(lca(t1,t2) == t1){
                if(lca(t2,x1) == t2 || lca(t2,y1) == t2)
                    fg = true;
            }
            if(lca(t1,t2) == t2){
                if(lca(t1,x2) == t1 || lca(t1,y2) == t1)
                    fg = true;
            }
            printf("%s\n", (fg == true ?"YES" : "NO")); 
        }
    }
    return 0;
}