ACM ICPC, Amman Collegiate Programming Contest (2018) Solution

Solution

A:Careful Thief

题意:给出n个区间,每个区间的每个位置的权值都是v,然后找长度为k的区间,使得这个区间的所有位置的权值加起来最大,输出最大权值, 所有区间不重叠

思路:贪心的想法,长度为k的区间的起始点肯定是某个区间的起始点,或者长度为k的区间的结束点肯定是某个区间的结束点。

因为存在最优的答案,它的起点不在某个区间的起点,那么只有两种情况。

1° 不属于任何已知区间

2° 在某个已知区间的内部

首先考虑第一种情况  如果不属于任何已知区间,那么根据贪心,我肯定能够往右移使得它是某个区间起点,这样得到的新的答案肯定大于等于原来的答案,因为我移动的这段区间的权值都为0

那么第二种情况,假如现在涵盖的区间横跨两个区间,那么我肯定能够右移结束点使得它与最后的那个区间的结束点对齐,或者左移起始点使得它跟最左边涵盖到的区间的起始点对齐,使得答案更大

然后双指针搞一搞

 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

 

posted @ 2018-08-15 20:53  Dup4  阅读(760)  评论(0编辑  收藏  举报