牧场行走(LCA)

神奇传送门

好吧,这题很有意思。。

第一眼撇的时候还以为是(SPFA)呜。。。。

然后发现要Q次询问就想到了LCA

但是发现不是求LCA。。

于是想到了一个神奇的定律:

两点的LCA一定在u到v的最短路上。。

并且也一定在两点与根节点的路上。

所以用dis[a]+dis[b]-2*dis[LCA(a,b)]就得到答案啦!

这道题有一个坑点!注意!

我们先来看一个测试:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main(){
    int x,y;
    scanf("%d%d",&x,&y);
    int k1=(int)(log(y-x+1.0)/log(2.0));
    int k2=0;
    while(1<<(k2+1)<=y-x+1)k2++;
    printf("%d     %d",k1,k2);
}

这看起来是等价的。。但是。。

输入:1 8

输出:2      3

恩,你没有看错,就是2、3.

事实是这样的:C++ 计算log(8)/log(2)时,得到的答案为(double)2.9999996。

强制转换为int后,变成了2;

但是这样就可以了QAQ

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main(){
    int num;
    int num2;
    double k=log(8.0)/log(2.0);
    num2=k;
    printf("%d",num2);
}

恩,这样就是啦awa

万恶的C++。。。

下面贴代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
struct data{
    int to,next,value;
}g[5000];
int head[1001];
bool qs[1001];
int id[1001];
int vs[5000];
int depth[5000];
int dp[5000][20];
int dd[1001];
int dfs_clock=1;
int n,q,num=0,root;
void ins(int a,int b,int v){
    g[++num].next=head[a];
    head[a]=num;
    g[num].to=b;
    g[num].value=v;
}
void dfs(int u,int fa,int d){
    id[u]=dfs_clock;
    vs[dfs_clock]=u;
    depth[dfs_clock++]=d;
    for(int i=head[u];i;i=g[i].next)
    {
        int v=g[i].to;
        if(v==fa) continue;
        dd[v]=dd[u]+g[i].value;
        dfs(v,u,d+1);
        vs[dfs_clock]=u;
        depth[dfs_clock++]=d;    
    }
}
void RMQ(int nn){
    for(int i=1;i<=nn;i++)
    dp[i][0]=i;
    for(int j=1;(1<<j)<=nn;j++)
    for(int i=1;i+(1<<j)-1<=nn;i++)
    {
        int a=dp[i][j-1];
        int b=dp[i+(1<<(j-1))][j-1];
        if(depth[a]<=depth[b])
        dp[i][j]=a;
        else 
        dp[i][j]=b;
    }
}
int cal(int x,int y){
    double k2=log(y-x+1.0)/log(2.0);
    int k=k2;
    int a=dp[x][k];
    int b=dp[y-(1<<k)+1][k];
    if(depth[a]<=depth[b])
    return a;
    else return b;    
}
int lca(int u,int v){
    int x=id[u];
    int y=id[v];
    if(x<y)
    return vs[cal(x,y)];
    else return vs[cal(y,x)];
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<n;i++)
    {
        int a,b,v;
        scanf("%d%d%d",&a,&b,&v);
        qs[b]=1;
        ins(a,b,v);ins(b,a,v);    
    }
    dfs(1,0,0);
    RMQ(dfs_clock-1);
    for(int i=1;i<=q;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",dd[a]+dd[b]-2*dd[lca(a,b)]);
    }
} 

不会RMQ的可以看我的传送门

当然,要打树上倍增的也是可以啦。。

代码就不贴了。

真是奇特的题目233~

posted @ 2017-05-10 17:03  ghostfly233  阅读(224)  评论(0编辑  收藏  举报