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;
}