ACM ICPC, Amman Collegiate Programming Contest (2018) Solution

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 }
View Code

 

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 }
View Code

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

 

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

 

 

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 }
View Code

 

 

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 }
View Code

 

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 }
View Code
相關文章
相關標籤/搜索