How far away ? HDU

来源:互联网 发布:学英语音标软件 编辑:程序博客网 时间:2024/05/01 19:59

题面

题意

给出一棵树,并询问任意两点间的距离.

方法

首先找到最小公共祖先,然后两端距离之和即为答案
第一步求出欧拉序(dfs搜索顺序),然后两点的公共祖先就是两点在欧拉序中之间深度最小的点,也就是区间最小值.
因此,首先求出欧拉序,然后求出各个点的深度以及它们到根节点的距离,并在欧拉序中用st表维护区间最小深度,两点间距离即为它们到根节点距离之和减去2*公共祖先到根节点的距离.

代码

#include<bits/stdc++.h>#define N 80010using namespace std;int T,n,m,first[N],bb,ou[N],oo,d[N],deep[N],wz[N],mm[N][30],kk[N][30];struct Bn{    int next,to,quan;}bn[N];void add(int u,int v,int qu){    bb++;    bn[bb].to=v;    bn[bb].quan=qu;    bn[bb].next=first[u];    first[u]=bb;}void dfs(int now,int last){    int p;    oo++;    ou[oo]=now;    p=first[now];    while(p!=-1)    {        if(bn[p].to==last)        {            p=bn[p].next;            continue;        }        deep[bn[p].to]=deep[now]+1;        d[bn[p].to]=d[now]+bn[p].quan;        dfs(bn[p].to,now);        oo++;        ou[oo]=now;        p=bn[p].next;    }}void get(){    int i,j;    for(i=1;i<=oo;i++)    {        mm[i][0]=deep[ou[i]];        kk[i][0]=ou[i];    }    for(i=1;(1 << i)<=oo;i++)    {        for(j=1;j+(1 << i)<=oo;j++)        {            if(mm[j][i-1]>mm[j+(1 << (i-1))][i-1])            {                mm[j][i]=mm[j+(1 << (i-1))][i-1];                kk[j][i]=kk[j+(1 << (i-1))][i-1];            }            else            {                mm[j][i]=mm[j][i-1];                kk[j][i]=kk[j][i-1];            }        }    }}int log(int u){    int res=0;    while(u)    {        res++;        u>>=1;    }    return res-1;}int ask(int u,int v){    int len;    len=v-u+1;    len=log(len);    if(mm[u][len]<mm[v-(1 << len)+1][len]) return kk[u][len];    return kk[v-(1 << len)+1][len];}int main(){    int i,j,k,o,p,q,l,r;    cin>>T;    while(T--)    {        bb=0;        memset(first,-1,sizeof(first));        scanf("%d%d",&n,&m);        for(i=1;i<=n-1;i++)        {            scanf("%d%d%d",&p,&q,&o);            add(p,q,o);            add(q,p,o);        }        oo=0;        deep[1]=1;        d[1]=0;        dfs(1,-1);        /*        for(i=1;i<=n;i++)        {            cout<<deep[i]<<" ";        }        cout<<endl<<endl;        /*        for(i=1;i<=oo;i++)        {            cout<<ou[i]<<' ';        }        cout<<endl;        //*/        memset(wz,-1,sizeof(wz));        for(i=1;i<=oo;i++)        {            if(wz[ou[i]]==-1) wz[ou[i]]=i;        }//      for(i=1;i<=2;i++) cout<<wz[i]<<' ';\        cout<<endl;        get();        for(i=1;i<=m;i++)        {            scanf("%d%d",&l,&r);//          cout<<wz[l]<<' '<<wz[r]<<endl;            if(wz[l]>wz[r]) swap(l,r);            k=ask(wz[l],wz[r]);//          cout<<k<<endl;            printf("%d\n",d[l]+d[r]-2*d[k]);        }    }}
原创粉丝点击