HDU2586 How far away ?(LCA在线RMQ-ST)

来源:互联网 发布:薛之谦 做作 知乎 编辑:程序博客网 时间:2024/05/22 13:48

题目点我点我点我


题目大意:求两个节点间最短距离。


解题思路:LCA(最近公共祖先),dis[i]表示从根节点到节点i的距离,所以要求节点u和节点v之间的距离则有dis[u]+dis[v]-2*dis[LCA(u,v)]。此处我是基于RMQ-ST写的。


第一次写这种题,过了样例却wa了一整页,度娘来的基本都是Tarjan算法的,没有多少是用RMQ写的,极其心累,调了一上午bug,才发现要先dfs再ST……ORZ。另在讨论区发现一组挺好的数据:

15 31 2 1001 3 2002 4 3002 5 1004 53 42 3结果400600300
/* ***********************************************┆  ┏┓   ┏┓ ┆┆┏┛┻━━━┛┻┓ ┆┆┃       ┃ ┆┆┃   ━   ┃ ┆┆┃ ┳┛ ┗┳ ┃ ┆┆┃       ┃ ┆┆┃   ┻   ┃ ┆┆┗━┓ 马 ┏━┛ ┆┆  ┃ 勒 ┃  ┆      ┆  ┃ 戈 ┗━━━┓ ┆┆  ┃ 壁     ┣┓┆┆  ┃ 的草泥马  ┏┛┆┆  ┗┓┓┏━┳┓┏┛ ┆┆   ┃┫┫ ┃┫┫ ┆┆   ┗┻┛ ┗┻┛ ┆************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <stack>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>using namespace std;#define rep(i,a,b) for (int i=(a),_ed=(b);i<=_ed;i++)#define per(i,a,b) for (int i=(b),_ed=(a);i>=_ed;i--)#define pb push_back#define mp make_pairconst int inf_int = 2e9;const long long inf_ll = 2e18;#define inf_add 0x3f3f3f3f#define mod 1000000007#define LL long long#define ULL unsigned long long#define MS0(X) memset((X), 0, sizeof((X)))#define SelfType intSelfType Gcd(SelfType p,SelfType q){return q==0?p:Gcd(q,p%q);}SelfType Pow(SelfType p,SelfType q){SelfType ans=1;while(q){if(q&1)ans=ans*p;p=p*p;q>>=1;}return ans;}#define Sd(X) int (X); scanf("%d", &X)#define Sdd(X, Y) int X, Y; scanf("%d%d", &X, &Y)#define Sddd(X, Y, Z) int X, Y, Z; scanf("%d%d%d", &X, &Y, &Z)int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}//#pragma comment(linker, "/STACK:102400000,102400000")const int N = 40010;int dp[2*N][20],dis[N];struct edge{    int to,next,w;}e[2*N];int last[N],cnt;void addedge(int u,int v,int w){    e[++cnt] = edge{v,last[u],w};last[u] = cnt;    e[++cnt] = edge{u,last[v],w};last[v] = cnt;}int vs[2*N];   //DFS访问的顺序int dep[2*N];  //节点的深度int ver[N];    //各个顶点在vs中首次出现的下标void dfs(int v,int p,int d,int &k){    ver[v] = k;    vs[k] = v;    dep[k++] = d;    for(int i=last[v];i!=-1;i=e[i].next)    {        if(e[i].to!=p)        {            dis[e[i].to]=dis[v]+e[i].w;            dfs(e[i].to,v,d+1,k);            vs[k] = v;            dep[k++] = d;        }    }}void st(int n){    for(int i=0;i<=n;i++)dp[i][0]=i;    for(int j=1;(1<<j)<=n;j++)    {        for(int i=1;i+(1<<j)-1<n;i++)        {            int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];            dp[i][j] = dep[a]<dep[b]?a:b;        }    }}int rmq(int l,int r){    int k = (int)(log(1.0*(r-l+1))/log(2.0));    int a = dp[l][k];    int b = dp[r-(1<<k)+1][k];    return dep[a]<dep[b]?a:b;}int LCA(int u,int v){    int x = ver[u], y = ver[v];    if(x>y)swap(x,y);    int res = rmq(x,y);    return vs[res];}int main(){//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);ios::sync_with_stdio(0);cin.tie(0);    Sd(cas);    while(cas--)    {        Sdd(n,q);        cnt = 0;        memset(last,-1,sizeof last);        for(int i=1;i<n;i++)        {            Sddd(u,v,w);            addedge(u,v,w);        }        for(int i=0;i<=n;i++) dis[i] = -1;        dis[1] = 0;        int k = 0;        dfs(1,-1,0,k);        st(2*n-1);        while(q--)        {            Sdd(l,r);            printf("%d\n",dis[l]+dis[r]-2*dis[LCA(l,r)]);        }    }return 0;}



0 0
原创粉丝点击