勇气小镇是一个有着n个房屋的小镇,为什么把它叫做勇气小镇呢,这个故事就要从勇气小镇成立的那天说起了,
修建小镇的时候,为了让小镇有特色,镇长特地只修了n-1条路,并且规定说,所有在勇气小镇的村民,每一次出门必须规划好路线,
路线必须满足在到达终点之前绝对不走回头路。每个人都要这样,不然那个人就不配在小镇生活下去,因为他没有这个勇气。
事实上,这并不能算一项挑战,因为n-1条路已经连通了每户人家,不回头地从起点到终点,只是一个时间上的问题。
由于小镇上的福利特别好,所以小懒入住了这个小镇,他规划了m次的行程,每次从L房屋到R房屋,他想问你他每次从L房屋到R房屋最少能走多少路。
输入的第一行是一个整数t,表示有t组数据
每组数据第一行是n,m两个数字,分别表示小镇上房屋的个数,和小懒计划的行程的数量。
之后第2行到第n行,每行三个整数a,b,c表示,a房屋与b房屋之间连接着一条距离为c的小路。
第n+1行到第n+m行,每行两个整数,L,R,代表一次小懒的询问,也就是询问小懒从L房屋走到R房屋所走的最近距离为多少。
对于每组测试数据输出m行,每行一个整数,代表小懒从询问的L到R需要走的最近的距离
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
t<=10
2<=n<=40000
1<=m<=200
1<=a<=n
1<=b<=n
1<=c<=40000
1<=L<=n
1<=R<=n
对于一棵树做离线查询, 输出2点间的距离
使用Tarjan离线查询即可, 需要做一点修改
dis[i]表示根节点(假设1号点为根) 第 i 点的距离, 在Tarjan中更新距离和lca(u, v)
对于查询u, v两点的距离, 输出dis[u]+dis[v]-2*dis[lca(u, v)]即可
#include
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const int inf = 1 << 30;
const int MAXN = 4e4+10;
int par[MAXN];
int findr(int u) {
if(par[u] == u) return u;
return par[u] = findr(par[u]);
}
void unite(int u, int v) {
u = findr(u);
v = findr(v);
if(u != v) par[v] = u;
}
bool vis[MAXN];
struct G {
int to, next, w;
} G[MAXN * 2];
int head[MAXN], ecnt;
void addEdge(int u, int v, int w) {
G[ecnt].to = v;
G[ecnt].w= w;
G[ecnt].next = head[u];
head[u] = ecnt++;
}
struct Query {
int q, next;
int id;
} query[MAXN * 2];
int h[MAXN], qcnt, Q;
void addQuery(int u, int v, int id) {
query[qcnt].q = v;
query[qcnt].next = h[u];
query[qcnt].id = id;
h[u] = qcnt++;
}
int lca[MAXN]; //询问边对应的最近公共祖先
int dis[MAXN]; //根节点到每个点的距离
int l[MAXN], r[MAXN];
void LCA(int u) {
vis[u] = true;
for(int i = head[u]; i != -1; i = G[i].next) {
int v = G[i].to;
if(vis[v]) continue;
dis[v] = dis[u] + G[i].w;
LCA(v);
unite(u, v);
}
for(int i = h[u]; i != -1; i = query[i].next){
int v = query[i].q;
if(vis[v])
lca[query[i].id] = findr(v);
}
}
void init(int N) {
for(int i = 0; i <= N; ++i) par[i] = i;
ecnt = qcnt = 0;
memset(head, -1, sizeof(head));
memset(h, -1, sizeof(h));
memset(vis, 0, sizeof(vis));
}
int main() {
int T, u, v, w, N, M;
cin >> T;
while(T--){
cin >> N >> M;
init(N);
for(int i = 1; i < N; ++i){
cin >> u >> v >> w;
addEdge(u, v, w);
addEdge(v, u, w);
}
for(int i = 1; i <= M; ++i){
cin >> l[i] >> r[i];
addQuery(l[i], r[i], i);
addQuery(r[i], l[i], i);
}
dis[1] = 0;
LCA(1);
for(int i = 1; i <= M; ++i)
cout << dis[l[i]]+dis[r[i]]-2*dis[lca[i]] << endl;
}
return 0;
}