[日常摸鱼]luogu3398仓鼠找sugar-树链剖分

本文探讨了一道关于树结构的算法题目,通过树剖的方法解决链的交集问题。介绍了如何利用深度优先搜索(DFS序)、最低公共祖先(LCA)和父子关系判断来优化算法,提高解题效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.luogu.org/problemnew/show/P3398

题意:一颗$n$个点的树,$q$次询问两条链$(a,b),(c,d)$是否有交

 


 

 

树剖裸题orz

一开始的想法是求出$lca_1=lca(a,b),lca_2=lca(c,d)$,对于深度大的那个$lca$用dfs序判断是否在另一条链上,然后到现在都不知道为什么一直wa…

改成判断深度大的那个$lca$是否和另外两个点的其中某个点有父子关系好像就行了…

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100005;
inline int read()
{
    int s=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){s=s*10+c-'0';c=getchar();}
    return s*f;
}
struct edge
{
    int to,nxt;
}edges[N<<1];
int n,q,tot,cnt;
int head[N<<1],size[N],son[N],dep[N],top[N],fa[N],tim[N];

inline void addEdge(int u,int v)
{
    edges[++cnt]=(edge){v,head[u]};
    head[u]=cnt;
}

#define cur edges[i].to

inline void dfs1(int x)
{
    size[x]=1;
    for(register int i=head[x];i;i=edges[i].nxt)
        if(cur!=fa[x])
        {
            fa[cur]=x;dep[cur]=dep[x]+1;
            dfs1(cur);size[x]+=size[cur];
            if(size[son[x]]<size[cur])son[x]=cur;
        }
}

inline void dfs2(int x,int t)
{
    top[x]=t;tim[x]=++tot;
    if(son[x])dfs2(son[x],t);
    for(register int i=head[x];i;i=edges[i].nxt)
        if(cur!=son[x]&&cur!=fa[x])dfs2(cur,cur);
}

#undef cur

inline int lca(int a,int b)
{
    while(top[a]!=top[b])
    {
        if(dep[top[a]]<dep[top[b]])swap(a,b);
        a=fa[top[a]];
    }
    if(dep[a]>dep[b])swap(a,b);
    return a;
}

int main()
{
    n=read();q=read();
    for(register int i=1;i<n;i++)
    {
        int u,v;u=read();v=read();
        addEdge(u,v);addEdge(v,u);
    }
    dfs1(1);dfs2(1,1);
    
    for(register int i=1;i<=q;i++)
    {
        int a,b,c,d,lca1,lca2,res;
        a=read();b=read();c=read();d=read();
        lca1=lca(a,b);lca2=lca(c,d);
        if(dep[lca1]<dep[lca2])
        {
            swap(lca1,lca2);
            swap(a,c);
            swap(b,d);
        }
        if(lca(lca1,c)==lca1||lca(lca1,d)==lca1)res=1;
        else res=0;
        
        if(res)printf("Y\n");
        else printf("N\n");
    }
    return 0;
}
View Code

 

如果有人知道一开始的方法为什么错了请务必告诉我orz

转载于:https://www.cnblogs.com/yoooshinow/p/8166843.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值