bzoj1787: [Ahoi2008]Meet 紧急集合

1787: [Ahoi2008]Meet 紧急集合

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 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

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;
}
View Code

 

posted @ 2013-08-15 18:40  SunnySnail  阅读(613)  评论(0编辑  收藏  举报