You are given n islands numbered from 1 to n and connected using n - 1 magical bridges. A greedy pirate wants to collect as many coins as possible by traveling through the bridges. Each bridge is a two-way bridge, but the pirate can only use the bridge at most twice. If a bridge connects islands u and v, then going from u to v gives c1 coins, and going from v to u gives c2.
Help the pirate to collect as many coins as he can knowing that he will start from some island x and finish at some island y.
Input
The first line contains an integer T (1 ≤ T ≤ 100) specifying the number of test cases.
The first line of each test case contains one integer n (2 ≤ n ≤ 105), in which n is the number of islands. The n - 1 lines follow, giving the bridges. Each line contains four integers u, v, c1, and c2 (1 ≤ u, v ≤ n, 1 ≤ c1, c2 ≤ 104), as describing in the statement above.
The next line contains an integer q (1 ≤ q ≤ 105), in which q is the number of queries. Then q lines follow, giving queries. Each query consists of two integers x and y (1 ≤ x, y ≤ n), in which x and y are the starting and finish islands, respectively.
The sum of n and q overall test cases does not exceed 25 × 105 for each.
Output
For each query, print a single line containing the maximum amount of money the greedy pirate can collect by traveling through the bridges starting from island x and finishing at island y.
Example
input
Copy
1 5 1 2 5 10 3 5 25 3 4 2 15 12 3 2 6 7 2 1 5 4 3
output
Copy
64 65
思路:首先把图画出来我们可以看到u到v的最大值为图的总边权-v到u的边权,那么就可以用floid去计算任意俩点的距离然后用总边权去减就得了,不过floid的复杂度为O(n3),明显不可能,所以得用另外一个方法,我们假设一个点为根结点,那么v到u的值我们可以这样计算:v到根节点的值+根节点到u的值-lca(u,v)到根节点的值-根节点到lca(u,v)的值(稍微思考一下就知道了),那么复杂度会被降低为O(nlgn),下面请看代码
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 100010;
int cnt = 1, u, v, a, b, m, n, t, sum;
struct Node{
int to;
int w1;
int w2;
int next;
}node[2 * maxn];
int head[maxn], p[maxn][30], depth[maxn], dis1[maxn], dis2[maxn];//dis1[u]表示u到根节点的值,dis2[u]表示根节点到u的值
void add(int u, int v, int w1, int w2) {
node[cnt].to = v;
node[cnt].w1 = w1;
node[cnt].w2 = w2;
node[cnt].next = head[u];
head[u] = cnt++;
}
void dfs(int u, int father) {
depth[u] = depth[father] + 1;
p[u][0] = father;
for (int i = 1; (1 << i) <= depth[u]; i++) {
p[u][i] = p[p[u][i - 1]][i - 1];
}
for (int i = head[u]; i != 0; i = node[i].next) {
int v = node[i].to;
int w1 = node[i].w1;
int w2 = node[i].w2;
if (v != father) {
dis1[v] = dis1[u] + w1;
dis2[v] = dis2[u] + w2;
dfs(v, u);
}
}
}
int lca(int a, int b) {
if (depth[a] > depth[b]) swap(a, b);
for (int i = 20; i >= 0; i--) {
if ((1 << i) <= depth[b] - depth[a]) {
b = p[b][i];
}
}
if (a == b) return a;
for (int i = 20; i >= 0; i--) {
if (p[a][i] ^ p[b][i]) {
a = p[a][i];
b = p[b][i];
}
}
return p[a][0];
}
void begin() {
cnt = 1;
sum = 0;
fill(head, head + maxn, 0);
fill(dis1, dis1 + maxn, 0);
fill(dis2, dis2 + maxn, 0);
fill(depth, depth + maxn, 0);
fill(p[0], p[0] + maxn * 30, 0);
}
int main() {
cin >> t;
while (t--) {
begin();
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d %d %d %d", &u, &v, &a, &b);
add(u, v, a, b);
add(v, u, b, a);
sum += a + b;
}
dfs(1, 0);
scanf("%d", &m);
while (m--) {
scanf("%d %d", &u, &v);
int Lca = lca(u, v);
printf("%d\n", sum - dis1[u] - dis2[v] + dis1[Lca] + dis2[Lca]);
}
}
}