LCA模板题(在线加离线)

来源:互联网 发布:2017淘宝数据魔方 编辑:程序博客网 时间:2024/06/15 10:57

How far away ?

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15241 Accepted Submission(s): 5772

Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.

Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 4e4 + 10;int n,m;int head[maxn];bool visit[maxn];ll dis[maxn];int Index[10*maxn];int First[maxn];int depth[maxn];int dp[10*maxn][25];int Log[2*maxn];int res;int root;int cnt;struct edge{    int u;    int v;    ll w;    int last;}Edge[2*maxn];void add(int u,int v,ll w){    Edge[cnt].u = u;    Edge[cnt].v = v;    Edge[cnt].w = w;    Edge[cnt].last = head[u];    head[u] = cnt++;}void init(){    root = 1;    dis[root] = 0;    cnt = 0;    res = 1;    memset(visit,false,sizeof(visit));    memset(head,-1,sizeof(head));    memset(dis,0,sizeof(dis));}void initRmq(){    Log[0] = -1;    for(int i = 1; i < res; i++)    {        Log[i] = (i&(i - 1)) == 0?Log[i - 1] + 1:Log[i - 1];    }    for(int i = 1; i < res; i++)    {        dp[i][0] = Index[i];    }    for(int j = 1; j < 20; j++)    {        for(int i = 1; i < res&&(i + (1<<j) - 1) < res; i++)        {            dp[i][j] = (depth[dp[i][j - 1]] < depth[dp[i + (1<<(j - 1))][j - 1]])?dp[i][j - 1]:dp[i + (1<<(j - 1))][j - 1];        }    }}int Rmq(int l,int r){    int dis = r - l + 1;    int j = Log[dis];    int result = (depth[dp[l][j]] < depth[dp[r - (1<<j) + 1][j]])?dp[l][j]:dp[r - (1<<j) + 1][j];    return result;}void dfs(int root){    if(visit[root]) return;    visit[root] = true;    for(int i = head[root]; i != -1; i = Edge[i].last)    {        int v = Edge[i].v;        ll w = Edge[i].w;        if(!visit[v])        {            dis[v] = dis[root] + w;            dfs(v);        }    }}void LCA(int root,int d){    First[root] = res;    depth[root] = d;    Index[res++] = root;    visit[root] = true;    for(int i = head[root]; i != -1; i = Edge[i].last)    {        int v = Edge[i].v;        if(!visit[v])        {            LCA(v,d + 1);            Index[res++] = root;        }    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m);        init();        int from,to;        ll w;        for(int i = 1; i <= n - 1; i++)        {            scanf("%d%d%lld",&from,&to,&w);            add(from,to,w);            add(to,from,w);        }        dfs(root);        memset(visit,false,sizeof(visit));        LCA(root,0);        initRmq();        for(int i = 1; i <= m; i++)        {            scanf("%d%d",&from,&to);            int f1 = First[from];            int f2 = First[to];            if(f1 > f2) swap(f1,f2);            int lca = Rmq(f1,f2);            ll ans = dis[from] + dis[to] - 2*dis[lca];            printf("%lld\n",ans);        }    }    return 0;}

离线算法:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 4e4 + 10;int n,m;int head[maxn];bool visit[maxn];ll dis[maxn];int father[maxn];int root;int cnt;struct ask{    int u;    int v;    int lca;}ask[300];struct edge{    int u;    int v;    ll w;    int last;}Edge[2*maxn];void add(int u,int v,ll w){    Edge[cnt].u = u;    Edge[cnt].v = v;    Edge[cnt].w = w;    Edge[cnt].last = head[u];    head[u] = cnt++;}int Find(int x){    if(x == father[x]) return x;    else return father[x] = Find(father[x]);}void init(){    root = 1;    dis[root] = 0;    cnt = 0;    memset(visit,false,sizeof(visit));    memset(head,-1,sizeof(head));    memset(dis,0,sizeof(dis));    for(int i = 1; i <= n; i++)    {        father[i] = i;    }}void dfs(int root){    if(visit[root]) return;    visit[root] = true;    for(int i = head[root]; i != -1; i = Edge[i].last)    {        int v = Edge[i].v;        ll w = Edge[i].w;        if(!visit[v])        {            dis[v] = dis[root] + w;            dfs(v);        }    }}void LCA(int root){    for(int i = 1; i <= m; i++)    {        int u = ask[i].u;        int v = ask[i].v;        if(root == u)        {            if(visit[v])            {                ask[i].lca = Find(v);            }        }        else if(root == v)        {            if(visit[u])            {                ask[i].lca = Find(u);            }        }    }    visit[root] = true;    for(int i = head[root]; i != -1; i = Edge[i].last)    {        int v = Edge[i].v;        if(!visit[v])        {            LCA(v);            father[v] = root;        }    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m);        init();        int from,to;        ll w;        for(int i = 1; i <= n - 1; i++)        {            scanf("%d%d%lld",&from,&to,&w);            add(from,to,w);            add(to,from,w);        }        for(int i = 1; i <= m; i++)        {            scanf("%d%d",&from,&to);            ask[i].u = from;            ask[i].v = to;        }        dfs(root);        memset(visit,false,sizeof(visit));        LCA(1);        for(int i = 1; i <= m; i++)        {            int lca = ask[i].lca;            int u = ask[i].u;            int v = ask[i].v;            ll ans = dis[u] + dis[v] - 2*dis[lca];            printf("%lld\n",ans);        }    }    return 0;}
1 0