Solutionnode
A:Careful Thiefc++
題意:給出n個區間,每一個區間的每一個位置的權值都是v,而後找長度爲k的區間,使得這個區間的全部位置的權值加起來最大,輸出最大權值, 全部區間不重疊ide
思路:貪心的想法,長度爲k的區間的起始點確定是某個區間的起始點,或者長度爲k的區間的結束點確定是某個區間的結束點。this
由於存在最優的答案,它的起點不在某個區間的起點,那麼只有兩種狀況。spa
1° 不屬於任何已知區間3d
2° 在某個已知區間的內部指針
首先考慮第一種狀況 若是不屬於任何已知區間,那麼根據貪心,我確定可以往右移使得它是某個區間起點,這樣獲得的新的答案確定大於等於原來的答案,由於我移動的這段區間的權值都爲0code
那麼第二種狀況,假如如今涵蓋的區間橫跨兩個區間,那麼我確定可以右移結束點使得它與最後的那個區間的結束點對齊,或者左移起始點使得它跟最左邊涵蓋到的區間的起始點對齊,使得答案更大blog
而後雙指針搞一搞ip
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define ll long long 6 7 #define N 100010 8 9 int t, m, k; 10 11 struct node 12 { 13 int l, r; 14 ll v; 15 ll sum; 16 inline node() {} 17 inline node(int l, int r, int v) : l(l), r(r), v(v) {} 18 19 inline void scan() 20 { 21 scanf("%d%d%lld", &l, &r, &v); 22 sum = (ll)(r - l + 1) * v; 23 } 24 25 inline bool operator < (const node& b) const 26 { 27 return l < b.l; 28 } 29 }arr[N]; 30 31 int main() 32 { 33 scanf("%d", &t); 34 while (t--) 35 { 36 scanf("%d%d", &m, &k); 37 for (int i = 1; i <= m; ++i) 38 arr[i].scan(); 39 40 sort(arr + 1, arr + m + 1); 41 int L, R; 42 int j = 1; 43 ll ans = 0; 44 ll tmp = 0; 45 for (int i = 1; i <= m; ++i) 46 { 47 L = arr[i].l; 48 R = L + k - 1; 49 while (arr[j].r <= R && j <= m) 50 { 51 tmp += arr[j].sum; 52 ++j; 53 } 54 ll res = 0; 55 if(j <= m) 56 { 57 res = arr[j].v * max(0, R - arr[j].l + 1); 58 } 59 tmp += res; 60 ans = max(ans, tmp); 61 tmp -= res; 62 tmp -= arr[i].sum; 63 } 64 tmp = 0; 65 j = m; 66 for(int i = m; i >= 1; --i) 67 { 68 R = arr[i].r; 69 L = R - k + 1; 70 while(arr[j].l >= L && j >= 1) 71 { 72 tmp += arr[j].sum; 73 --j; 74 } 75 ll res = 0; 76 if(j >= 1) 77 { 78 res = arr[j].v * max(0, arr[j].r - L + 1); 79 } 80 tmp += res; 81 ans = max(ans, tmp); 82 tmp -= res; 83 tmp -= arr[i].sum; 84 } 85 printf("%lld\n",ans); 86 } 87 return 0; 88 }
B:Friends and Cookies
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define ll long long 6 7 #define N 1010 8 9 int t, n; 10 11 ll x; 12 13 ll ans[N]; 14 15 int main() 16 { 17 scanf("%d", &t); 18 while (t--) 19 { 20 scanf("%lld%d", &x, &n); 21 if (n == 1) 22 { 23 printf("%lld\n", x); 24 continue; 25 } 26 ll len = n + n - 2; 27 ll base = x / len; 28 ll MOD = x % len; 29 for (int i = 1; i <= n; ++i) 30 { 31 if (i != 1 && i != n) 32 ans[i] = base << 1; 33 else 34 ans[i] = base; 35 } 36 for (int i = 1; i <= n && i <= MOD; ++i) 37 { 38 ans[i]++; 39 } 40 for (int i = n + 1; i <= MOD; ++i) 41 { 42 ans[2 * n - i]++; 43 } 44 for (int i = 1; i <= n; ++i) printf("%lld%c", ans[i], " \n"[i == n]); 45 } 46 return 0; 47 }
C:Flip the Bits
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int t, n; 6 7 int main() 8 { 9 scanf("%d", &t); 10 while (t--) 11 { 12 scanf("%d", &n); 13 if (n & 1) 14 { 15 puts("1"); 16 continue; 17 } 18 else 19 { 20 int ans = 1; 21 while ((n & 1) == 0 && n) 22 { 23 ++ans; 24 n >>= 1; 25 } 26 printf("%d\n", ans); 27 } 28 } 29 return 0; 30 }
D:Magic Sticks
題意:有n * m 的矩形 每一個矩形四條邊,從這些邊中選取一個邊的集合,使得任意兩條邊不相交,而且每一個矩形至少有一條邊被選中
思路:
偶數 * 偶數
奇數 * 奇數
奇數 * 偶數
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define ll long long 6 7 #define INFLL 0x3f3f3f3f3f3f3f3f 8 9 int t; 10 ll n, m; 11 12 int main() 13 { 14 scanf("%d", &t); 15 while (t--) 16 { 17 scanf("%lld%lld", &n, &m); 18 19 ll ans = INFLL; 20 21 if (n % 2 == 0 && m % 2 == 0) 22 { 23 ans = min(ans, (n / 2) * (m + 1)); 24 ans = min(ans, (m / 2) * (n + 1)); 25 } 26 else if (n % 2 == 1 && m % 2 == 1) 27 { 28 ans = min(ans, ((n + 1) / 2) * m); 29 ans = min(ans, ((m + 1) / 2) * n); 30 } 31 else 32 { 33 if (n % 2 == 0) swap(n, m); 34 ans = min(ans, ((n + 1) / 2 * m)); 35 ans = min(ans, ((n + 1) / 2) * (m / 2) + (n / 2) * (m + 2) / 2); 36 } 37 printf("%lld\n", ans); 38 } 39 return 0; 40 }
E:N - Dimensional Grid
題意: 在n維的空間,給你每一個空間的長度,求有多少個格子相鄰
思路:
一維:a1 - 1
二維:(a1 - 1) * a2 + (a2 - 1) * a1
大膽推廣到高維:(a1 - 1) * (a2 + ... + an) + (a2 - 1) * (a1 + a3 + ... + an) ...
而後前綴後綴搞一搞
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int MOD = 1e9 + 7; 8 #define N 100010 9 10 int t,n; 11 ll arr[N],brr[N],crr[N]; 12 13 int main() 14 { 15 scanf("%d",&t); 16 while(t--) 17 { 18 scanf("%d",&n); 19 for(int i = 1; i <= n; ++i) 20 { 21 scanf("%lld",&arr[i]); 22 } 23 brr[0] = 1; 24 for(int i = 1; i <= n; ++i) 25 { 26 brr[i] = (brr[i - 1] * arr[i]) % MOD; 27 } 28 crr[n + 1] = 1; 29 for(int i = n; i >= 1; --i) 30 { 31 crr[i] = (crr[i + 1] * arr[i]) %MOD; 32 } 33 ll ans = 0; 34 for(int i = 1; i <= n; ++i) 35 { 36 ans = (ans + brr[i - 1] * (arr[i] - 1) %MOD * crr[i + 1] %MOD) %MOD; 37 } 38 printf("%lld\n",ans); 39 } 40 return 0; 41 }
F:Minimum Sum of Array
題意:給出n個數,若是ai 能夠整除aj,那麼 ai 能夠變成aj,求儘量變換後,全部數的總和最小
思路:顯然,貪心的想法是,對於每一個數咱們都給它變成這個數列中它跟它不互素的最小數,用相似素數篩法的思想去篩
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 7 #define M 1000010 8 9 #define ll long long 10 11 int t, n; 12 int arr[N]; 13 int vis[M]; 14 int used[M]; 15 16 int main() 17 { 18 scanf("%d", &t); 19 while (t--) 20 { 21 scanf("%d", &n); 22 for (int i = 1; i <= n; ++i) 23 scanf("%d", arr + i); 24 sort(arr + 1, arr + 1 + n); 25 for (int i = 1; i <= arr[n]; ++i) 26 vis[i] = i, used[i] = 1; 27 for (int i = 1; i <= n; ++i) 28 { 29 int v = arr[i]; 30 if (v >= (arr[n] / 2 + 2)) break; 31 if (vis[v] == v && used[v] == 1) 32 { 33 used[v] = 0; 34 for (int j = v * 2; j <= arr[n]; j += v) 35 vis[j] = min(vis[j], v); 36 } 37 } 38 ll ans = 0; 39 for (int i = 1; i <= n; ++i) ans += vis[arr[i]]; 40 printf("%lld\n", ans); 41 } 42 return 0; 43 }
G:Power of String
題意:給出一個式子,求修改最多k個字符,使得這個式子的值最大
思路:根據這個式子,咱們能夠知道假如一個字符有n個,那麼這n個字符的值是(n * (n - 1)) / 2 * ASCII(ch)
那麼咱們能夠把全部字符放在一塊兒看
貪心的想法,若是存在答案,確定是若干個小於等於k個字符變成同一個字符,由於這樣會使得式子更大
那麼咱們枚舉26個字符,使這個字符使要變成的字符
而後咱們考慮,儘可能讓個數小的去換掉,那麼個數小於等於k的字符就能夠去作01揹包,而後再枚舉26位來當作補充
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define READ freopen("Test.in", "r", stdin); 6 #define N 100010 7 #define M 5010 8 #define ll long long 9 #define INFLL 0x3f3f3f3f3f3f3f3f 10 11 int t, n, K; 12 char s[N]; 13 14 ll num[200]; 15 16 inline ll F(ll x) 17 { 18 return (x * (x - 1)) / 2; 19 } 20 21 inline ll Get(char c, ll pre, ll now) 22 { 23 ll res = 0; 24 res = F(now) * c; 25 res -= F(pre) * c; 26 return res; 27 } 28 29 ll dp[M]; 30 ll f[M]; 31 32 inline ll work(char c) 33 { 34 for (int i = 1; i <= K; ++i) f[i] = -INFLL; 35 for (int i = 'a'; i <= 'z'; ++i) 36 { 37 if (i == c) continue; 38 if (num[i] == 0) continue; 39 dp[0] = 0; 40 for (int j = 1; j <= K; ++j) dp[j] = -INFLL; 41 for (int j = 'a'; j <= 'z'; ++j) 42 { 43 if (j == c || j == i) continue; 44 for (int l = K; l >= num[j]; --l) 45 dp[l] = max(dp[l], dp[l - num[j]] + Get(j, num[j], 0)); 46 } 47 ll tot = num[i]; 48 for (int j = K; j >= 0; --j) 49 { 50 if (tot + j <= K) 51 dp[tot + j] = max(dp[tot + j], dp[j] + Get(i, tot, 0)); 52 else 53 dp[K] = max(dp[K], dp[j] + Get(i, tot, tot - K + j)); 54 } 55 for (int j = 1; j <= K; ++j) f[j] = max(f[j], dp[j]); 56 } 57 ll res = 0; 58 for (int i = 1; i <= K; ++i) 59 res = max(res, f[i] + Get(c, num[c], num[c] + i)); 60 return res; 61 } 62 63 int main() 64 { 65 #ifdef LOCAL 66 READ; 67 #endif 68 scanf("%d", &t); 69 while (t--) 70 { 71 scanf("%d%d", &n, &K); 72 scanf("%s", s); 73 memset(num, 0, sizeof num); 74 for (int i = 0; s[i]; ++i) 75 num[s[i]]++; 76 ll ans = 0, tmp = 0; 77 for (int i = 'a'; i <= 'z'; ++i) 78 ans += F(num[i]) * i; 79 tmp = ans; 80 for (int i = 'a'; i <= 'z'; ++i) 81 ans = max(ans, tmp + work(i)); 82 printf("%lld\n", ans); 83 } 84 return 0; 85 }
H:Making Friends
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 2010 6 7 int t, n; 8 9 int arr[N]; 10 11 int main() 12 { 13 scanf("%d", &t); 14 while (t--) 15 { 16 scanf("%d", &n); 17 for (int i = 1; i <= n * 2; ++i) 18 scanf("%d", arr + i); 19 int ans = 0; 20 for (int i = 1; i <= n; ++i) 21 ans = max(ans, arr[i] + arr[2 * n - i + 1]); 22 printf("%d\n", ans); 23 } 24 return 0; 25 }
I: Split the Number
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int t, x, n; 6 7 int main() 8 { 9 scanf("%d", &t); 10 while (t--) 11 { 12 scanf("%d%d", &x, &n); 13 if (x < n) 14 { 15 puts("-1"); 16 continue; 17 } 18 int base = x / n; 19 int MOD = x % n; 20 for (int i = 1; i <= n; ++i) 21 { 22 printf("%d%c", base + ((n - i + 1 <= MOD) ? 1 : 0), " \n"[i == n]); 23 } 24 } 25 return 0; 26 }
J:T-Shirts Dilemma
題意:給出 a b v 在a - b 中找出一個連續子區間,使得這個區間內的全部數按位或運算的和小於v 找出子區間的最大長度
思路:
咱們能夠從最高有效位往最低有效爲看 用 vi 表示 v 的第i位 ai bi 同理
若是vi == 0 && ai == 0 && bi == 0 那麼咱們跳到下一位繼續看
若是vi == 1 && ai == 0 && bi == 0 那麼答案就是 b - a + 1 由於 將a - b 的全部數按位或起來的值確定小於 v' (v' = 將v的第i位邊爲0, 小於i的全部位都變爲1) 而且 v' < v
若是 vi == 0 && ai == 0 && bi == 1
那麼咱們能夠將bi 變爲0 而後將小於i的b的全部位都變爲1 再往下一位看 這樣的操做至關於縮小了b的範圍,對答案沒有影響
若是vi == 1 && ai == 1 && bi == 1
顯然 咱們能夠將 vi ai bi 都變爲0 而後看下一位操做 是沒有影響的
若是vi == 0 && ai == 1 && bi == 1 那麼此時答案顯然爲0 由於a > v
若是vi ==1 && ai == 0 && bi == 1
若是此時 vi的低位都爲1 那麼答案就是 b - a + 1
若是不是 咱們能夠 令c = 將vi 變爲0 而後全部低位都變爲1 答案爲 c - a + 1
或者 咱們 能夠將 a 變成 c + 1 而後 三個數的第i位都變爲0 繼續找下去
爲何將a 變成 c + 1 而不考慮 c + 1 一下的數
由於 c | c + 1 必然大於等於v 而 等於的狀況 就是 b - a + 1 已經特判過
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define ll long long 6 7 int t; 8 9 ll a, b, v; 10 11 inline ll work(ll a, ll b, ll v, int i) 12 { 13 if (i == -1) 14 return 1ll; 15 16 ll D = (1ll << i) - 1; 17 18 bool ai = a & (D + 1), bi = b & (D + 1), vi = v & (D + 1); 19 20 if (vi && !ai && !bi) 21 return b - a + 1; 22 if (!vi && ai && bi) 23 return 0; 24 if (vi && ai && bi) 25 return work(a & D, b & D, v & D, i - 1); 26 if (!vi && !ai && !bi) 27 return work(a, b, v, i - 1); 28 if (!vi && !ai && bi) 29 return work(a, (1ll << i) - 1, v, i - 1); 30 31 if (v == ((1ll << (i + 1)) - 1)) 32 return b - a + 1; 33 34 ll c = (1ll << i) - 1; 35 return max(c - a + 1, work(0, b & D, v & D, i - 1)); 36 } 37 38 int main() 39 { 40 #ifdef LOCAL 41 freopen("Test.in", "r", stdin); 42 #endif 43 scanf("%d", &t); 44 while (t--) 45 { 46 scanf("%lld%lld%lld", &a, &b, &v); 47 printf("%lld\n", work(a, b, v, 60)); 48 } 49 return 0; 50 }
K:League of Demacia
題意:給定一個原點,給定一條邊長爲z的線段,使得原點爲中點,角度不定。從該線段兩端點向同一方向畫出兩條射線,使得這一區域的點超過m個。
思路:顯然咱們能夠枚舉每個點在射線上的狀況,而後o(n)枚舉每一個點的狀況。肯定某一點是否在區域內可經過向量的數量積與z/2的比較以及向量積來肯定是否爲同一方向。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 1010 6 7 const double eps = 1e-8; 8 9 inline int sgn(double x) 10 { 11 if(fabs(x) < eps) return 0; 12 else if(x > 0) return 1; 13 else return -1; 14 } 15 16 struct Point{ 17 double x, y; 18 inline Point(){} 19 inline Point(double x, double y) : x(x), y(y){} 20 21 inline void input() 22 { 23 scanf("%lf %lf",&x, &y); 24 } 25 26 inline Point operator - (const Point &b) const 27 { 28 return Point(x - b.x, y - b.y); 29 } 30 31 inline double operator ^ (const Point &b) const 32 { 33 return x * b.y - y * b.x; 34 } 35 36 inline double operator * (const Point &b) const 37 { 38 return x * b.x + y * b.y; 39 } 40 41 inline Point operator + (const Point &b) const 42 { 43 return Point(x + b.x, y + b.y); 44 } 45 46 inline Point operator / (const double &k) const 47 { 48 return Point(x / k, y / k); 49 } 50 51 inline double distance(const Point &b) const 52 { 53 return hypot(x - b.x, y - b.y); 54 } 55 56 inline Point rotate(Point p, double angle) 57 { 58 Point v = (*this) - p; 59 double c = cos(angle), s = sin(angle); 60 return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c); 61 } 62 }P[N]; 63 64 int n, m; 65 double z; 66 67 int main() 68 { 69 int t; 70 scanf("%d",&t); 71 while(t--) 72 { 73 scanf("%d %d %lf",&n, &m, &z); 74 double r = z / 2; 75 for(int i = 1; i <= n; ++i) 76 { 77 P[i].input(); 78 } 79 bool flag = false; 80 for(int i = 1; i <= n; ++i) 81 { 82 Point a = P[i]; 83 double d = a.distance(Point(0, 0)); 84 if(sgn(d) == 0) a = Point(1, 0); 85 else if(sgn(d - r) <= 0) a = P[i]; 86 else a = P[i].rotate(Point(0, 0), acos(r / d)); 87 88 a = a / a.distance(Point(0, 0)); 89 int cnt = 1; 90 for(int j = 1; j <= n; ++j) 91 { 92 if(i == j) continue; 93 double tmp = fabs(P[j] * a); 94 if(sgn(tmp - r) <= 0 && sgn(a ^ P[j]) <= 0) cnt++; 95 if(cnt >= m) break; 96 } 97 if(cnt >= m) 98 { 99 flag = true; 100 break; 101 } 102 } 103 puts(flag ? "Yes" : "No"); 104 105 } 106 return 0; 107 }
L:Lazy Teacher
題意:對一個nm的矩陣填色,一共有k個顏色,相鄰的方塊不能同一種顏色,求填色方案。
思路:首先注意到n很小,其次當咱們按順序填方格時,影響這一方格以及接下來的方格的只會是前5塊,所以咱們只用記錄前5塊方格便可。所以對於每個長度爲6的方塊實際上最多用到6種顏色,咱們將其離散化後,那麼最遠的方塊p1<1,p2<2,p3<3,p4<4,p5<5
而後咱們能夠枚舉當前要填充顏色的方塊的顏色,從0-5,其中5表明和前面5塊互不相同個顏色,而後搜索一下(或者說dp?),最後剪剪枝。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int MOD = 1e9 + 7; 8 9 #define M 10010 10 11 int val[6], pos[6]; 12 ll dp[6][M][2][3][4][5]; 13 14 int limit; 15 int n, m, k; 16 17 inline void update() 18 { 19 memset(val, 0, sizeof val); 20 for (int i = 0, color = 1; i < 5; ++i) 21 { 22 if (val[pos[i]] != 0) 23 { 24 pos[i] = val[pos[i]] - 1; 25 } 26 else 27 { 28 val[pos[i]] = color; 29 pos[i] = color - 1; 30 color++; 31 } 32 } 33 } 34 35 inline ll solve(int x, int y, int p2, int p3, int p4, int p5) 36 { 37 if (x == n) return solve(0, y + 1, p2, p3, p4, p5); 38 if (y == m) return 1; 39 if (dp[x][y][p2][p3][p4][p5] != -1) return dp[x][y][p2][p3][p4][p5]; 40 int res = 0; 41 int up; 42 if (n == 5) 43 { 44 up = 0; 45 } 46 else if (n == 4) 47 { 48 up = p2; 49 } 50 else if (n == 3) 51 { 52 up = p3; 53 } 54 else if (n == 2) 55 { 56 up = p4; 57 } 58 else if (up = 1) 59 { 60 up = p5; 61 } 62 for (int color = 0; color < limit; ++color) 63 { 64 if (color == up && y != 0) continue;//up 65 if (color == p5 && x != 0) continue;//left 66 pos[0] = p2, pos[1] = p3, pos[2] = p4, pos[3] = p5, pos[4] = color; 67 update();//離散化 68 res = (res + (color == 5 ? k - 5 : 1) * solve(x + 1, y, pos[1], pos[2], pos[3], pos[4])) % MOD;//5 means new color 69 } 70 dp[x][y][p2][p3][p4][p5] = res; 71 return res; 72 } 73 74 int main() 75 { 76 int t; 77 scanf("%d", &t); 78 while (t--) 79 { 80 scanf("%d %d %d", &n, &m, &k); 81 limit = min(k, 6); 82 memset(dp, -1, sizeof dp); 83 ll ans = solve(0, 0, 0, 0, 0, 0); 84 printf("%lld\n", ans); 85 } 86 return 0; 87 }
M:Greedy Pirate
題意:給出一棵樹,n - 1條邊,一條邊上兩個權值,而後每次詢問u -> v 問 從 u - > v的最大花費,每條邊能夠走兩次
思路:顯然 答案是全部邊權和減去 終點到LCA的權值和 減去 LCA 到 起點的權值和
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 100010; 6 const int DEG = 20; 7 8 typedef long long ll; 9 int n; 10 11 struct Edge{ 12 int to,nxt; 13 int w1,w2; 14 inline Edge(){} 15 inline Edge(int to,int nxt,int w1,int w2):to(to),nxt(nxt),w1(w1),w2(w2){} 16 }edge[maxn << 1]; 17 18 int head[maxn],tot; 19 20 inline void addedge(int u,int v, int w1, int w2) 21 { 22 edge[tot] = Edge(v,head[u],w1,w2); 23 head[u] = tot++; 24 } 25 26 int fa[maxn][DEG]; 27 ll dis1[maxn];// from fa 28 ll dis2[maxn];// to fa 29 int deg[maxn]; 30 31 void init() 32 { 33 tot = 0; 34 memset(dis1, 0, sizeof dis1); 35 memset(dis2, 0, sizeof dis2); 36 memset(head, -1, sizeof head); 37 } 38 39 inline void BFS(int root) 40 { 41 queue<int>q; 42 deg[root] = 0; 43 fa[root][0] = root; 44 q.push(root); 45 while(!q.empty()) 46 { 47 int tmp = q.front(); 48 q.pop(); 49 for(int i = 1; i < DEG; ++i) 50 { 51 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 52 } 53 for(int i = head[tmp]; ~i; i = edge[i].nxt) 54 { 55 int v = edge[i].to; 56 if(v == fa[tmp][0]) continue; 57 dis1[v] = dis1[tmp] + edge[i].w1; 58 dis2[v] = dis2[tmp] + edge[i].w2; 59 deg[v] = deg[tmp] + 1; 60 fa[v][0] = tmp; 61 q.push(v); 62 } 63 } 64 } 65 66 int LCA(int u,int v) 67 { 68 if(deg[u] > deg[v]) swap(u, v); 69 int hu = deg[u], hv = deg[v]; 70 int tu = u; 71 int tv = v; 72 for(int det = hv - hu, i = 0; det; det >>= 1, ++i) 73 { 74 if(det & 1) 75 tv = fa[tv][i]; 76 } 77 if(tu == tv) return tu; 78 for(int i = DEG - 1; i >= 0; --i) 79 { 80 if(fa[tu][i] == fa[tv][i]) continue; 81 tu = fa[tu][i]; 82 tv = fa[tv][i]; 83 } 84 return fa[tu][0]; 85 } 86 87 int main() 88 { 89 int t; 90 scanf("%d",&t); 91 while(t--) 92 { 93 init(); 94 scanf("%d",&n); 95 ll sum = 0; 96 for(int i = 1; i < n; ++i) 97 { 98 int u, v, w1, w2; 99 scanf("%d %d %d %d",&u, &v, &w1, &w2); 100 sum += w1 + w2; 101 addedge(u, v, w1, w2); 102 addedge(v, u, w2, w1); 103 } 104 BFS(1); 105 int q; 106 scanf("%d",&q); 107 while(q--) 108 { 109 int u,v; 110 scanf("%d %d",&u,&v); 111 int root = LCA(u,v); 112 ll ans = sum - (dis2[v] - dis2[root] + dis1[u] - dis1[root]); 113 printf("%lld\n",ans); 114 } 115 } 116 return 0; 117 }