旅行

来源:互联网 发布:淘宝刷评价兼职 编辑:程序博客网 时间:2024/04/27 18:15

旅行


  • Description

N-1座桥连接着N个岛屿,每座桥都连接着某两个不同的岛屿,从任意一个岛屿都可以到达所有的其他岛屿,过桥需要缴纳人民币1元的过桥费。
由于某些不可透露的原因,Jason和他的2个小伙伴可以在任意一个岛屿集合,但是希望总过桥费最少。
现在,由你来确定集合的岛屿编号,使得总过桥费最少。

  • Input Format

输入数据有input.txt提供。第一行有两个整数N和M,表示岛屿的个数和询问次数,岛屿编号从1到N。
接下来N-1行,每行有两个正整数X、Y,表示编号为X的岛屿和编号为Y的岛屿之间有一座桥。
最后还有M行,每行有三个正整数A、B、C,表示Jason和他的两个小伙伴所在岛屿的编号。

  • Output Format

结果输出到output.txt。一共有M行,每行两个整数P、Q,用一个空格隔开。其中第i行表示第i次询问集合的地点在编号为P的岛屿,需要花费的最少过桥费为Q。

  • Sample Output

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

  • Sample Output

1 0
1 1
1 2
2 4
2 3

  • Hint

30%的数据中,N≤200,M≤200;
60%的数据中,N≤2,000,M≤2,000;
100%的数据中,N≤200,000,M≤200,000;


  • 分析

暴力解法:枚举每一个结点作为集合点,跑一遍树,记录答案,复杂度为O(n2)
正解:对于一棵树上的三个点,我们可以分成一下三种情况:

  1. 三个点两两的最近公共祖先相同,即三个点分别属于一个结点的三颗子树。
  2. 一个结点是另两个点最近公共祖先的祖先。
  3. 三个结点在一条链上。

这样一来就可以很便捷地处理路径长度了。


#include <cstdio>#include <cstring>#include <algorithm>#define Max 200001using namespace std;struct Edge{int to,next;}E[2*Max];int Deep[Max],Father[Max][22],last[Max],n,m,tot,x,y,z,ans1,ans2,ans3,ans;void Addline(int u,int v){    E[++tot].to=v; E[tot].next=last[u]; last[u]=tot;    E[++tot].to=u; E[tot].next=last[v]; last[v]=tot;}void Dfs(int fa,int u){    Father[u][0]=fa; Deep[u]=Deep[fa]+1;    for (int i=1;i<=21;i++) Father[u][i]=Father[Father[u][i-1]][i-1];    for (int i=last[u];i;i=E[i].next){        if (fa==E[i].to) continue;        Dfs(u,E[i].to);    }}int Lca(int u,int v){    if (Deep[v]>Deep[u]) swap(u,v);    for (int i;Deep[u]>Deep[v];u=Father[u][i-1]){        for (i=1;i<=21 && Deep[Father[u][i]]>=Deep[v];i++);    }    for (int i;u!=v;u=Father[u][i-1],v=Father[v][i-1]){        for (i=1;i<=21 && Father[u][i]!=Father[v][i];i++);    }    return u;}void Work(int x,int y,int z){    int xy=Lca(x,y),yz=Lca(y,z),xz=Lca(x,z);    if (xy!=x && xy!=y) printf("%d %d\n",xy,(Deep[x]+Deep[y]-2*Deep[xy])+(Deep[xy]+Deep[z]-2*Deep[Lca(xy,z)]));    else if (xy==x) printf("%d %d\n",x,(Deep[y]-Deep[x])+(Deep[x]+Deep[z]-2*Deep[xz]));    else printf("%d %d\n",y,(Deep[x]-Deep[y])+(Deep[y]+Deep[z]-2*Deep[yz]));}int main(){    freopen("in.txt","r",stdin);    freopen("out.txt","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1;i<n;i++){        scanf("%d%d",&x,&y);        Addline(x,y);    }    Dfs(0,1);    for (int i=1;i<=m;i++){        scanf("%d%d%d",&x,&y,&z);        /*if (Deep[x]<Deep[y]) swap(x,y);        if (Deep[x]<Deep[z]) swap(x,z);        if (Deep[y]<Deep[z]) swap(y,z);*/        int xy=Lca(x,y),yz=Lca(y,z),xz=Lca(x,z);        if (xy==yz && yz==xz){            printf("%d %d\n",xy,Deep[x]+Deep[y]+Deep[z]-3*Deep[xy]);            continue;        }        if (xz==yz) Work(x,y,z);        else if (xy==yz) Work(x,z,y);        else if (xy==xz) Work(y,z,x);    }    fclose(stdin); fclose(stdout);    return 0;}
0 0
原创粉丝点击