1558:聚会 ybt
1558:聚会 ybt 题解(看似很难,其实要是摸清了实质这就是个大水题)
上题目
1558:聚会
时间限制: 1000 ms 内存限制: 524288 KB
提交数: 82 通过数: 56
【题目描述】
原题来自:AHOI 2008
Y
岛风景美丽宜人,气候温和,物产丰富。Y 岛上有 N 个城市,有 N 条城市间的道路连接着它们。每一条道路都连接某两个城市。幸运的是,小可可通过这些道路可以走遍 Y
岛的所有城市。神奇的是,乘车经过每条道路所需要的费用都是一样的。
小可可,小卡卡和小 Y
经常想聚会,每次聚会,他们都会选择一个城市,使得三个人到达这个城市的总费用最小。
由于他们计划中还会有很多次聚会,每次都选择一个地点是很烦人的事情,所以他们决定把这件事情交给你来完成。他们会提供给你地图以及若干次聚会前他们所处的位置,希望你为他们的每一次聚会选择一个合适的地点。
【输入】
第一行两个正整数,N
和 M
。分别表示城市个数和聚会次数;
后面有 N
行,每行用两个正整数 A 和 B 表示编号为 A 和编号为 B 的城市之间有一条路。城市的编号是从 1 到 N
的;
再后面有 M
行,每行用三个正整数表示一次聚会的情况:小可可所在的城市编号,小卡卡所在的城市编号以及小 Y
所在的城市编号。
【输出】
一共有 M
行,每行两个数 P 和 C,用一个空格隔开。表示第 i 次聚会的地点选择在编号为 P 的城市,总共的费用是经过 C
条道路所花费的费用。
【输入样例】
6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6
【输出样例】
5 2 2 5 4 1 6 0
【提示】
数据范围与提示:
40% 的数据中,1≤N
;
100% 的数据中,1≤N
。
乍一看这道题正常人的脑子里都会想到最短路 在不看这一节的标题的情况下
但是这道题的本质却是找规律。。。。在纸上画一画就很容易想到
我们分别找出这三个点的LCA,会发现三个LCA当中必有两个相同的点(可以数学证明但是我不会)
而最终要去的那个点就是除了上述两点之外的第三个点
#include<bits/stdc++.h> using namespace std; const int N=5e5+1; int n,m,tot; int next[N<<1],head[N<<1],f[N<<1][21],Dep[N<<1],to[N<<1]; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } inline void Add(int from,int pos) { next[++tot]=head[from]; head[from]=tot; to[tot]=pos; } inline void Pre(int u,int fa) { Dep[u]=Dep[fa]+1; f[u][0]=fa; for(int i=1;i<=19;i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=head[u];i;i=next[i]) { if(to[i]==fa) continue; //dis[to[i]]=dis[u]+1; Pre(to[i],u); } } inline int LCA(int x,int y) { if(Dep[x]<Dep[y]) swap(x,y); for(int i=19;i>=0;i--) { if(Dep[f[x][i]]>=Dep[y]) x=f[x][i]; if(x==y) return x; } for(int i=19;i>=0;i--) { if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } } return f[x][0]; } inline int Q(int x,int y) { return (Dep[x]+Dep[y]-2*Dep[LCA(x,y)]); } inline int query(int x,int y,int z,int end) { return (Q(x,end)+Q(y,end)+Q(z,end)); } int main() { n=read();m=read(); int x,y,z; int A,B,C; for(int i=1;i<n;i++) { x=read();y=read(); Add(x,y); Add(y,x); } Pre(1,1); for(int i=1;i<=m;i++) { x=read();y=read();z=read(); A=LCA(x,y); B=LCA(x,z); C=LCA(y,z); if(A==B) printf("%d %d\n",C,query(x,y,z,C)); else if(A==C) printf("%d %d\n",B,query(x,y,z,B)); else printf("%d %d\n",A,query(x,y,z,A)); } return 0; }