• NKOJ P3815 树上的询问 (LCA 倍增)(复习距离倍增)


    评测说明 : 1000ms
    问题描述

    现有一棵 n 个节点的树,树上每条边的长度均为 1。给出 m 个询问,每次询问两个节 点 x,y,求树上到 x,y 两个点距离相同的节点数量。 

    输入格式

    第一个整数 n,表示树有 n 个点。
    接下来 n-1 行每行两整数 a,b,表示从 a 到 b 有一条边。
    接下来一行一个整数 m,表示有 m 个询问。
    接下来 m 行每行两整数 x,y,询问到 x 和 y 距离相同的点的数量。 

    输出格式

    共 m 行,每行一个整数表示询问的答案。 

    样例输入


    1 2 
    1 3 
    2 4 
    2 5 
    3 6 
    3 7 

    1 2 
    4 5
    2 3 

     
     
     
    思路: 被坑了好久 一直没调出来  复习了一波LCA 后 终于A 了 注意 倍增的用法 即GOUP 操作
     
    顺便复习一下 距离倍增 
    code:
    g[x][i]=g[x][i-1]+g[fa[x][i-1]][i-1];

    dis 求法

    for(i=0;i<=ss;i++)
        if(k&(1<<i))dis+=g[x][i],x=fa[x][i];
    if(x==y)return dis;
    for(i=s;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
            {
                dis+=g[x][i];x=fa[x][i];
    
                dis+=g[y][i];y=fa[y][i];
            }
        return dis+=g[x][0]+g[y][0];
     
    code:
    //
    #include<bits/stdc++.h>
    using namespace std;
    #define maxnn 600000
    int f[maxnn][100];
    int las[maxnn],nex[maxnn],en[maxnn],tot;
    int n,m;
    int dep[maxnn];
    int x,y;
    int size[maxnn];
    void dfs(int v,int fa)
    {
        dep[v]=dep[fa]+1;
        f[v][0]=fa;
        int s=ceil(log2(n));
        for(int i=1;i<=s;i++)
        {
            f[v][i]=f[f[v][i-1]][i-1];
        }
        for(int i=las[v];i;i=nex[i])
        {
            int u=en[i];
            if(u!=fa)
            {
                dfs(u,v);
                size[v]+=size[u];
            }
        }
        return ;
    }
    void add(int a,int b)
    {
        en[++tot]=b;
        nex[tot]=las[a];
        las[a]=tot;
    }
    int goup(int x,int s)
    {
        int k=ceil(log2(n));
        for(int i=0;i<=k;i++)
        {
            if((s&(1<<i)))
            {
                x=f[x][i];
            }
        }
        return x;
    }
    int lca(int x,int y)
    {
        if(dep[x]<dep[y])swap(x,y);
        x=goup(x,dep[x]-dep[y]);
        if(x==y) return y;
        int s=ceil(log2(dep[x]));
        for(int i=s;i>=0;i--)
        {
            if(f[x][i]!=f[y][i])
            {
                x=f[x][i];
                y=f[y][i];
            }
        }
        return f[x][0];
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++) size[i]=1;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs(1,0);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int k1=0,k=0;
            scanf("%d%d",&x,&y);
            if(y==x) {cout<<n<<endl;continue;}
            if(dep[x]==dep[y])
            {
                int k=dep[x]-dep[lca(x,y)];
                int k1=n-size[goup(x,k-1)]-size[goup(y,k-1)];
                cout<<k1<<endl;
                continue;
            }
            if((abs((dep[x]-dep[y])))&1) {cout<<0<<endl;continue;}
            if(dep[x]<dep[y])
            swap(x,y);
            k=(dep[y]+dep[x]-2*dep[lca(x,y)])/2;
            int p1=goup(x,k-1);int p2=goup(x,k);
            k1=size[p2]-size[p1];
            cout<<k1<<endl;
            
        } 
     } 
    刀剑映出了战士的心。而我的心,漆黑且残破
  • 相关阅读:
    Shiro入门学习之shi.ini实现授权(三)
    Shiro入门学习之shi.ini实现认证及源码分析(二)
    猜字母游戏(Java)
    二维数组的语法
    鸡兔同笼问题(Java)
    成绩统计程序(Java)
    18位身份证验证(Java)加入身份证输入验证是否满足18位代码(修订稿)
    18位身份证验证(Java)
    键盘输入字符插入定义数组中并按顺序排列
    一个随机验证码且不重复的小程序以及求随机输入一组数组中的最大值(Java)
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11324624.html
Copyright © 2020-2023  润新知