bzoj1787: [Ahoi2008]Meet 紧急集合
1787: [Ahoi2008]Meet 紧急集合
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 698 Solved: 282
[Submit][Status]
Description
Input
Output
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
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
题意:一些点和联通它们的边,三个人在站在不同的点上,要集合到同一点上去,问最小的总步数。
三个人,两个两个算lca,有两对是相同的,那个不同的点便是要求的,算出三个点到所求出的点的总距离。(注意数组范围)
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <vector> #include <queue> #include <algorithm> #define PII pair<int,int> #define LL long long #define M 10 using namespace std; const int MAXN = 500100; int n,m; vector< PII > edge[MAXN<<1]; int dp[MAXN<<1][25]; int depth; int b[MAXN*4],bn; //深度序列 int f[MAXN]; //对应深度序列中的结点编号 int p[MAXN]; //结点在深度序列中的首位置 int d[MAXN]; //到根的深度 void dfs(int x,int fa,int deep) { int tmp = ++ depth; b[++bn] = tmp; f[tmp] = x; p[x] = bn; d[x]=deep; for(unsigned i=0; i<edge[x].size(); i++) { int y = edge[x][i].first; if (y==fa) continue; dfs(y,x,deep+1); b[++bn] = tmp; } } void rmq_init(int n) //以深度序列做rmq { for(int i=1; i<=n; i++) dp[i][0]=b[i]; int m = floor(log(n*1.0)/log(2.0)); for(int j=1; j<=m; j++) for (int i=1; i<=n-(1<<j)+1; i++) dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } int rmq(int l,int r) { int k = floor(log((r-l+1)*1.0)/log(2.0)); return min( dp[l][k] , dp[r-(1<<k)+1][k] ); } int lca(int a,int b) { if (p[a]>p[b]) swap(a,b); return f[ rmq(p[a],p[b]) ]; } int main() { cin>>n >>m; for(int i=0; i<MAXN; i++) edge[i].clear(); depth = bn = 0; int x,y; for(int i=2; i<=n; i++) { scanf("%d%d",&x,&y); edge[x].push_back(make_pair(y,i)); edge[y].push_back(make_pair(x,i)); } dfs(1,0,0); rmq_init(bn); int z,t,q,r; for(int i=0; i<m; i++) { scanf("%d%d%d",&x,&y,&z); int s=d[x]+d[y]+d[z]; int w; t=lca(x,y); q=lca(y,z); r=lca(x,z); if(t==q) { w=lca(r,y); printf("%d %d\n",r,s-d[w]*2-d[r]); } else if(t==r) { w=lca(q,x); printf("%d %d\n",q,s-d[w]*2-d[q]); } else if(r==q) { w=lca(t,z); printf("%d %d\n",t,s-d[w]*2-d[t]); } } return 0; }