• [bzoj1787][Ahoi2008]紧急集合


    Description

    给定一棵大小为n的树,有m组询问,每组询问给三个点x,y,z,求到这三个点距离和最小的点及最小距离和.

    Input

    第一行两个数n,m.

    接下来(n-1)行,每行两个数x,y表示xy有一条边.

    最后m行,每行3个数x,y,z,为一组询问.

    Output

    一共m行,每行两个数,表示到三个点距离和最小的点及最小距离和.

    Sample Input

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

    Sample Output

    5 2
    2 5
    4 1
    6 0

    HINT

    n,m$leq$5$	imes$10^5

    Solution

    3个点两两求lca,只会有2种情况:

    1.lca均相同;

    2.有1lca与其他不同.

    如果均相同,lca为答案,否则为与其他不同的那个lca.

    (画图简单推推即可理解)

    距离可用深度O(1)求出.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define K 20
    #define N 500005
    using namespace std;
    struct graph{
        int nxt,to;
    }e[N<<1];
    int f[N][K],g[N],dep[N],a,b,c,n,m,x,y,z,cnt;
    stack<int> s;
    inline int read(){
        int ret=0;char c=getchar();
        while(!isdigit(c))
            c=getchar();
        while(isdigit(c)){
            ret=(ret<<1)+(ret<<3)+c-'0';
            c=getchar();
        }
        return ret;
    }
    inline void addedge(int x,int y){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
    }
    inline void dfs(int u){
        dep[u]=1;s.push(u);
        while(!s.empty()){
            u=s.top();s.pop();
            if(u==1) for(int i=0;i<K;++i)
                f[u][i]=1;
            else for(int i=1;i<K;++i)
                f[u][i]=f[f[u][i-1]][i-1];
            for(int i=g[u];i;i=e[i].nxt)
                if(!dep[e[i].to]){
                    dep[e[i].to]=dep[u]+1;
                    f[e[i].to][0]=u;
                    s.push(e[i].to);
                }
        }
    }
    inline int swim(int x,int h){
        for(int i=0;h;++i,h>>=1)
            if(h&1) x=f[x][i];
        return x;
    }
    inline int lca(int x,int y){
        if(dep[x]<dep[y]){
            int t=x;x=y;y=t;
        }
        x=swim(x,dep[x]-dep[y]);
        if(x==y) return x;
        int i;
        while(true){
            for(i=0;f[x][i]!=f[y][i];++i);
            if(!i) return f[x][0];
            x=f[x][i-1];y=f[y][i-1];
        }
    } 
    inline void init(){
        n=read();m=read();
        for(int i=1,j,k;i<n;++i){
            j=read();k=read();
            addedge(j,k);addedge(k,j);
        }
        dfs(1);
        while(m--){
            x=read();y=read();z=read();
            a=lca(x,y);b=lca(y,z);c=lca(x,z);
            if(a==b&&b==c)
                printf("%d %d
    ",a,dep[x]+dep[y]+dep[z]-dep[a]*3);
            else if(a==b) printf("%d %d
    ",c,dep[x]+dep[y]+dep[z]-dep[c]-(dep[a]<<1));
            else if(a==c) printf("%d %d
    ",b,dep[x]+dep[y]+dep[z]-dep[b]-(dep[a]<<1));
            else printf("%d %d
    ",a,dep[x]+dep[y]+dep[z]-dep[a]-(dep[b]<<1));
        }
    }
    int main(){
        freopen("meet.in","r",stdin);
        freopen("meet.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    拉格朗日乘子基本概念
    "模式识别与机器学习"读书笔记——2.3(2)
    [raw]人工智能方向调查
    Android !No Launcher activity found!错误
    [raw]ubuntu在当前目录右键打开终端
    Android, 读取大型文件报错
    Blueman Ubuntu的蓝牙管理器
    VMware下Ubuntu8.04 方向键失效的解决方法
    无线中间人攻击初探
    【经验】短接 Flash 解决二次量产金士顿 DTI G2 4GB U盘(群联PS225139)问题
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6011258.html
Copyright © 2020-2023  润新知