洛谷 P3398 LCA判断交点

题目链接:点我

题意:

在一个无根树中,判断两条链是否相交。
范围:1e5个点 1e5次询问
第一行两个正整数n和q,表示这棵树节点的个数和询问的个数。
接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。
接下来q行,每行四个正整数a、b、c和d,表示节点编号,求ab链和cd链是否有交点。
实例:
5 5
2 5
4 2
1 3
1 4
5 1 5 1
2 2 1 4
4 1 3 4
3 1 1 5
3 5 1 4
输出:
对于每个询问,如果有公共点,输出大写字母“Y”;否则输出“N”。
Y
N
Y
Y
Y

题解:

树种两条链有交点,必然存在如下规律:其中一条链,两端点的最近公共祖先在另外一条链上。

代码:

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define maxn 500005
#define IOS ios::sync_with_stdio(false)

struct edge
{
    int next, to;
};

edge ff[2 * maxn];
int head[2 * maxn], num;
void add(int from, int to)
{
    ff[++num].next = head[from];
    ff[num].to = to;
    head[from] = num;
}

int Eu[2 * maxn], id;	//记录欧拉序列
int dd[maxn];			//每一点的深度
int hId[maxn];		//记录每一点对应欧拉序列第一次出现的位置(映射)
bool vis[maxn];
int dis[maxn];//记录到根节点的距离
void dfs(int fa,int x, int d)
{
    dis[x]=dis[fa]+1;
    dd[x] = d;
    Eu[++id] = x;
    hId[x] = id;
    vis[x] = true;
    for (int i = head[x]; i != -1; i = ff[i].next)
    {
        if (vis[ff[i].to] == false)
        {
            dfs(x,ff[i].to, d + 1);
            Eu[++id] = x;
        }
    }
}

int f[2 * maxn][32];
int res[2 * maxn][32];

void ST_Init(int n)
{
    for (int i = 1; i <= n; i++)
    {
        f[i][0] = dd[Eu[i]];
        res[i][0] = Eu[i];
    }
    int depth = (int)(log2(n));
    for (int j = 1; j <= depth; j++)
        for (int i = 1; i <= n - (1 << j) + 1; i++)
        {
            if (f[i][j - 1]<f[i + (1 << (j - 1))][j - 1])
            {
                f[i][j] = f[i][j - 1];
                res[i][j] = res[i][j - 1];
            }
            else
            {
                f[i][j] = f[i + (1 << (j - 1))][j - 1];
                res[i][j] = res[i + (1 << (j - 1))][j - 1];
            }
        }
}

int ST_Query(int l, int r)
{
    int p = (int)(log2(r - l + 1));
    if (f[l][p]<f[r - (1 << p) + 1][p])
        return res[l][p];
    else
        return res[r - (1 << p) + 1][p];
}

int get_lca(int x,int y)
{
    int l,r;
    if (hId[x]<hId[y])
        l = hId[x], r = hId[y];
    else
        l = hId[y], r = hId[x];
    return ST_Query(l, r);
}

void init()
{
    memset(head, -1, sizeof(head));
    memset(vis, 0, sizeof(vis));
    num = 0;
}

int main()
{
    IOS;
    int n, m, k;
    cin>>n>>m;
    k=1;
    init();
    for (int i = 0; i<n - 1; i++)
    {
        int x, y;
        cin>>x>>y;
        add(x, y), add(y, x);
    }

    dfs(k,k, 1);
    ST_Init(id);

    for (int i = 0; i<m; i++)
    {
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        int lca1=get_lca(x1,y1);
        int lca2=get_lca(x2,y2);
        int d1=dis[x1]+dis[y1]-2*dis[lca1]; //the distance of x1->y1
        int d2=dis[x2]+dis[y2]-2*dis[lca2]; // the distance of x2->y2
        bool flag=false;
        //判断lca1是否在x2->y2中
        int d3=dis[x2]+dis[lca1]-2*dis[get_lca(x2,lca1)];//the distance of x2->lca1
        int d4=dis[y2]+dis[lca1]-2*dis[get_lca(y2,lca1)];//the distance of y2->lca1
        if(d3+d4==d2) //lca1在x2->y2中
        {
            flag=true;
        }
        else
        {
            //判断lca2是否在x1->y1中
            int d5=dis[x1]+dis[lca2]-2*dis[get_lca(x1,lca2)];//the distance of x1->lca2
            int d4=dis[y1]+dis[lca2]-2*dis[get_lca(y1,lca2)];//the distance of y1->lca2
            if(d5+d4==d1)//lca2在x1->y1中
            {
                flag=true;
            }
        }
        if(flag)
            cout<<"Y\n";
        else
            cout<<"N\n";
    }
    return 0;
}

发布了41 篇原创文章 · 获赞 2 · 访问量 1216

猜你喜欢

转载自blog.csdn.net/qq_41418281/article/details/104065961
今日推荐