BZOJ 1602: [Usaco2008 Oct]牧场行走【LCA】

1602: [Usaco2008 Oct]牧场行走

Time Limit: 5 Sec Memory Limit: 64 MB

Description

N头牛(2<=n<=1000)别人被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头牛在第i块牧场吃草。 这n块土地被n-1条边连接。 奶牛可以在边上行走,第i条边连接第Ai,Bi块牧场,第i条边的长度是Li(1<=Li<=10000)。 这些边被安排成任意两头奶牛都可以通过这些边到达的情况,所以说这是一棵树。 这些奶牛是非常喜欢交际的,经常会去互相访问,他们想让你去帮助他们计算Q(1<=q<=1000)对奶牛之间的距离。

Input

  • 第一行:两个被空格隔开的整数:N和Q
    • 第二行到第n行:第i+1行有两个被空格隔开的整数:AI,BI,LI
  • 第n+1行到n+Q行:每一行有两个空格隔开的整数:P1,P2,表示两头奶牛的编号。

Output

  • 第1行到第Q行:每行输出一个数,表示那两头奶牛之间的距离。

Sample Input

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

Sample Output

2
7

题解

这题最笨的想法都能过,但是我写了个LCA,求P1,P2的最近公共祖先,然后就前缀和记一下就可了。

代码如下

 #include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,Q,Dep[1005],fa[1005][30],Sum[1005];
int lnk[1005],W[2005],son[2005],nxt[2005],tot;
void Add(int x,int y,int w){son[++tot]=y;W[tot]=w;nxt[tot]=lnk[x];lnk[x]=tot;}
void DFS(int x,int f,int D){
    fa[x][0]=f;Dep[x]=D;
    for(int j=lnk[x];j;j=nxt[j])
    if(son[j]^f) Sum[son[j]]=Sum[x]+W[j],DFS(son[j],x,D+1);
}
void Updata(){
    for(int j=1;(1<<j)<n;j++)
    for(int i=1;i<=n;i++) fa[i][j]=-1;
    for(int j=1;(1<<j)<n;j++)
    for(int i=1,t;i<=n;i++)
    if(fa[i][j-1]^-1) t=fa[i][j-1],fa[i][j]=fa[t][j-1];
}
int Get(int p,int q){
    if(Dep[q]>Dep[p]) swap(p,q);
    int Log=0;
    for(;(1<<Log)<Dep[p];Log++);Log--;
    for(int j=Log;j>=0;j--)
    if(fa[p][j]^-1&&Dep[fa[p][j]]>=Dep[q]) p=fa[p][j];
    if(p==q) return p;
    for(int j=Log;j>=0;j--)
    if(fa[p][j]^-1&&fa[p][j]^fa[q][j]) p=fa[p][j],q=fa[q][j];
    return fa[p][0];
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    scanf("%d%d",&n,&Q);
    for(int i=1;i<n;i++){
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        Add(x,y,w);Add(y,x,w);
    }
    DFS(1,0,0);Updata();
    for(int i=1;i<=Q;i++){
        int x,y;scanf("%d%d",&x,&y);
        int Root=Get(x,y);
        printf("%d\n",Sum[x]+Sum[y]-2*Sum[Root]);
    }
    return 0;
}
posted @ 2018-05-14 18:27  XSamsara  阅读(157)  评论(0编辑  收藏  举报