欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

P3398 仓鼠找sugar 又一次血的教训

程序员文章站 2023-01-01 12:52:01
做什么题都要注意数组的大小,不要犯下数组越界的错误(温馨(狠心)提示); 做了好多遍就是不对,原来是【20】的数组,在for下循环1——》20,神奇爆零; 链接:https://www.luogu.org/problemnew/show/P3398 这道题有一个性质: 判断树上两条路径是否有交点或重 ......

做什么题都要注意数组的大小,不要犯下数组越界的错误(温馨(狠心)提示);

做了好多遍就是不对,原来是【20】的数组,在for下循环1——》20,神奇爆零;

链接:https://www.luogu.org/problemnew/show/p3398

这道题有一个性质:

判断树上两条路径是否有交点或重叠部分,那就是

有a,b一条路径,还有c,d这条路径。

要是这两条路径相交或重合,

那么要不是lca(a,b)在cd上,就是lca(c,d)在ab上;

显然易得啊(反正我是不会证明,背下来记好了);

 

倍增lca

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2000050;
int pre[maxn],other[maxn],last[maxn],l;
int n,q;
void add(int x,int y)
{
    l++;
    pre[l]=last[x];
    last[x]=l;
    other[l]=y;
}
int dep[maxn],jump[maxn][20];
void dfs(int u)
{
    for(int p=last[u];p;p=pre[p])
    {
        int v=other[p];
        if(v==jump[u][0]) continue;
        dep[v]=dep[u]+1;
        jump[v][0]=u;
        dfs(v);
    }
}

int lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=0;i<=17;i++)
    {
        if((dep[u]-dep[v])&(1<<i)) u=jump[u][i];
    }
    if(u==v) return u;
    for(int j=17;j>=0;j--)
    {
        if(jump[u][j]!=jump[v][j])
        {
            u=jump[u][j];
            v=jump[v][j];
        }
    }
    return jump[u][0];
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    dfs(1);
    for(int j=1;j<=17;j++)//17就够了,不要搞什么20 
    {
        for(int i=1;i<=n;i++)
        {
            jump[i][j]=jump[jump[i][j-1]][j-1];
        }
    }
    for(int i=1;i<=q;i++)
    {
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        int x=lca(a,b);
        int y=lca(c,d);
        int l1=dep[a]+dep[b]-2*dep[x];//a->b路径长度 
        int l2=dep[c]+dep[d]-2*dep[y];//c->d路径长度 
        if(dep[c]+dep[x]-2*dep[lca(x,c)]+dep[d]+dep[x]-2*dep[lca(x,d)]==l2)//c->x->d==l2
        {
            printf("y\n");
            continue;
        }
            if(dep[a]+dep[y]-2*dep[lca(a,y)]+dep[b]+dep[y]-2*dep[lca(y,b)]==l1)//a->y->b==l1,就是两条线段长度和等于整个线段长度 
        {
            printf("y\n");
            continue;
        }
        printf("n\n");
    }
    return 0;
}