2016-2017 CT S03E07: Codeforces Trainings Season 3 Episode 7

 

A. Yet Another Problem with Strings

题意:

给出$n$个字符串$S_i$,要求支持两种操作:

  • 在第$i$个字符串后增加一个字符$c$
  • 给出一个字符串$T$,询问是否有一个串$S_i$是$T$的子串。

强制在线,保证$\sum S_i, \sum T \leq 2 \cdot 10^5$

 

思路:

考虑暴力做法即枚举每个$S_i$然后询问$T$中的每个等长的子串是否等于$S_i$。

但是一个小优化是可以把所有长度相同的$S_i$放在一起做,用std::map记录哈希值。

并且注意到$\sum S_i \leq 2 \cdot 10^5$,所以所有的$S_i$只有$\sqrt{2 \cdot 10^5}$种长度。

暴力即可。

 

B. Pen Pineapple Apple Pen

Solved.

题意:将一个序列合并成一个数。

思路:分类讨论一下, 水。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxn = 1e5 + 10;
 6 
 7 char str[maxn];
 8 
 9 bool solve()
10 {
11     int len = strlen(str + 1);
12     if(len == 1) return true;
13     while(len % 2 == 0) len = len >> 1;
14     if(len != 1) return false;
15     len = strlen(str + 1);
16     for(int i = 1; i <= len; i += 2) if(str[i] != 'P' && str[i + 1] != 'P') return false;
17     return true;
18 }
19 
20 int main()
21 {
22     int t;
23     scanf("%d", &t);
24     while(t--)
25     {
26         scanf("%s", str + 1);
27         puts(solve() ? "YES" : "NO");
28     }
29     return 0;
30 }
View Code

 

C. Stickmen

Solved.

题意:找有几个小人

思路:枚举$i, j$两个点作为中间那条线的端点, 再枚举公共点计算贡献。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const ll MOD = 1e9 + 7;
 8 const int maxn = 1e3;
 9 
10 int n, m;
11 ll fac[maxn];
12 ll inv[maxn];
13 ll invfac[maxn];
14 int du[maxn];
15 int mp[maxn][maxn];
16 
17 void Init()
18 {
19     fac[1] = inv[1] = invfac[1] = 1;
20     fac[0] = inv[0] = invfac[0] = 1;
21     for(int i = 2; i < maxn; ++i)
22     {
23         fac[i] = fac[i - 1] * i % MOD;
24         inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD;
25         invfac[i] = invfac[i - 1] * inv[i] % MOD;
26     }
27 }
28 
29 ll C(int n, int m)
30 {
31     if(n < 0 || m < 0) return 0;
32     if(m > n) return 0;
33     return fac[n] * invfac[m] % MOD * invfac[n - m] % MOD;
34 }
35 
36 int merge(int x, int y)
37 {
38     int res = 0;
39     for(int i = 1; i <= n; ++i) if(mp[x][i] == 1 && mp[y][i] == 1) res++;
40     return res;
41 }
42 
43 int main()
44 {
45     Init();
46     while(~scanf("%d %d", &n, &m))
47     {
48         memset(mp, 0, sizeof mp);
49         memset(du, 0, sizeof du);
50         for(int i = 1, x, y; i <= m; ++i)
51         {
52             scanf("%d %d", &x, &y);
53             du[x]++, du[y]++;
54             mp[x][y] = mp[y][x] = 1;
55         }
56         ll ans = 0;
57         for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) if(mp[i][j] && i != j)
58         {
59             int x = du[i] - 1, y = du[j] - 1;
60             int same = merge(i, j);
61             ans = (ans  + C(x, 3) * C(y, 2) % MOD)% MOD;
62             
63             ans = (ans - C(x - 1, 2) * C(y - 1, 1) % MOD * same % MOD) % MOD;
64             ans = (ans + C(x - 2, 1) * C(same, 2) % MOD) % MOD;
65         }
66         printf("%lld\n", ans);
67     }
68     return 0;
69 }
View Code

 

D. Strange Queries

Solved.

题意:询问$i \in [L_1, R_1],j \in [L_2, R_2]  有多少对(i, j) 使得 a_i = a_j$

思路:$f[i][j]表示第i个块对前j个块的贡献,f2[i][j]表示a_i对前j个块的贡献$

$整块整块处理,边边角角处理$

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define ll long long
  5 #define N 50010
  6 #define S 150
  7 #define unit 450
  8 int n, a[N], q;
  9 int pos[N], posl[unit], posr[unit];
 10 ll f[unit][unit], f2[N][unit];
 11 int cnt[N];
 12 
 13 int main()
 14 {
 15     while (scanf("%d", &n) != EOF)
 16     {
 17         for (int i = 1; i <= n; ++i) pos[i] = (i - 1) / S + 1;
 18         for (int i = 1; i <= n; ++i)
 19         {
 20             if (i == 1 || pos[i] != pos[i - 1]) 
 21                 posl[pos[i]] = i;
 22 //            cout << i << " " << pos[i] << endl;
 23             posr[pos[i]] = i;  
 24 //            printf("%d %d\n", posl[pos[i]], posr[pos[i]]);
 25         }
 26 //        for (int i = 1; i <= n; ++i) cout << i << " " << pos[i] << endl;
 27 //        for (int i = 1; i <= n; ++i)
 28 //            printf("%d %d\n", posl[pos[i]], posr[pos[i]]);
 29         memset(f, 0, sizeof f);
 30         memset(f2, 0, sizeof f2); 
 31         memset(cnt, 0, sizeof cnt);
 32         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
 33         for (int i = 1; i <= pos[n]; ++i)   
 34         {  
 35             for (int j = posl[i]; j <= posr[i]; ++j)
 36                 ++cnt[a[j]];
 37             for (int j = 1; j <= n; ++j) 
 38             {
 39                 f[i][pos[j]] += cnt[a[j]];
 40                 f2[j][i] += cnt[a[j]];
 41             }
 42             for (int j = posl[i]; j <= posr[i]; ++j)
 43                 --cnt[a[j]];
 44         } 
 45         for (int i = 1; i <= pos[n]; ++i)
 46             for (int j = 1; j <= pos[n]; ++j)
 47                 f[i][j] += f[i][j - 1];
 48         for (int i = 1; i <= n; ++i)
 49             for (int j = 1; j <= pos[n]; ++j)
 50                 f2[i][j] += f2[i][j - 1]; 
 51         scanf("%d", &q);
 52         int l[2], r[2];
 53         while (q--)
 54         {
 55             for (int i = 0; i < 2; ++i)
 56                 scanf("%d%d", l + i, r + i);
 57             if (pos[l[1]] == pos[r[1]])
 58             {
 59                 swap(l[0], l[1]);
 60                 swap(r[0], r[1]);
 61             }
 62             ll res = 0; 
 63             if (pos[l[0]] == pos[r[0]])
 64             {
 65                 if (pos[l[1]] == pos[r[1]])
 66                 {
 67                     for (int i = l[0]; i <= r[0]; ++i) 
 68                         ++cnt[a[i]];
 69                     for (int i = l[1]; i <= r[1]; ++i) 
 70                         res += cnt[a[i]];
 71                     for (int i = l[0]; i <= r[0]; ++i)
 72                         --cnt[a[i]];
 73                 }
 74                 else
 75                 {
 76                     int L = pos[l[1]] + 1;
 77                     int R = pos[r[1]] - 1;
 78                     for (int i = l[0]; i <= r[0]; ++i)
 79                     {
 80                         res += f2[i][R] - f2[i][L - 1];
 81                         ++cnt[a[i]];
 82                     }
 83                     for (int i = l[1]; i <= posr[pos[l[1]]]; ++i)
 84                         res += cnt[a[i]];
 85                     for (int i = posl[pos[r[1]]]; i <= r[1]; ++i)
 86                         res += cnt[a[i]];
 87                     for (int i = l[0]; i <= r[0]; ++i)
 88                         --cnt[a[i]];
 89                 }
 90             }
 91             else
 92             {
 93                 int L[2] = {pos[l[0]] + 1, pos[l[1]] + 1};
 94                 int R[2] = {pos[r[0]] - 1, pos[r[1]] - 1};
 95                 for (int i = L[0]; i <= R[0]; ++i)
 96                     res += f[i][R[1]] - f[i][L[1] - 1]; 
 97                 for (int i = l[0]; i <= posr[pos[l[0]]]; ++i) 
 98                 {
 99                     res += f2[i][R[1]] - f2[i][L[1] - 1];
100                     ++cnt[a[i]];
101                 }
102                 for (int i = posl[pos[r[0]]]; i <= r[0]; ++i)
103                 {
104                     res += f2[i][R[1]] - f2[i][L[1] - 1];
105                     ++cnt[a[i]];
106                 }
107                 for (int i = l[1]; i <= posr[pos[l[1]]]; ++i) 
108                 {
109                     res += f2[i][R[0]] - f2[i][L[0] - 1];
110                     res += cnt[a[i]];
111                 }
112                 for (int i = posl[pos[r[1]]]; i <= r[1]; ++i)
113                 {
114                     res += f2[i][R[0]] - f2[i][L[0] - 1];
115                     res += cnt[a[i]];
116                 }
117                 for (int i = l[0]; i <= posr[pos[l[0]]]; ++i) 
118                     --cnt[a[i]];
119                 for (int i = posl[pos[r[0]]]; i <= r[0]; ++i)
120                     --cnt[a[i]];
121             }
122             printf("%lld\n", res);
123         }
124     }
125     return 0;
126 }
View Code

 

E. Bravebeart

Solved.

题意:给出n个人和n匹马, 每个人和每匹马都有自己的能力值, 每个人选择一匹马, 那么每个人的权值就是个人能力值乘上马的权值, 求是否存在一种方案, 使得第一个人的权值最大。

思路:排序, 水

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int INF = 0x3f3f3f3f;
 6 const int maxn = 1e5 + 10;
 7 
 8 int n;
 9 int w[maxn], h[maxn];
10 
11 bool solve(int tmp)
12 {
13     for(int i = n - 1; i >= 1; --i)
14     {
15         if(w[i] * h[n - 1 - i + 1] >= tmp) return false; 
16     }
17     return true;
18 }
19 
20 int main()
21 {
22     int t;
23     scanf("%d", &t);
24     while(t--)
25     {
26         scanf("%d", &n);
27         for(int i = 1; i <= n; ++i) scanf("%d", w + i);
28         for(int i = 1; i <= n; ++i) scanf("%d", h + i);
29         int tmp = w[1];
30         w[1] = INF;
31         sort(w + 1, w + 1 + n);
32         sort(h + 1, h + 1 + n);
33         tmp *= h[n];
34         puts(solve(tmp) ? "YES" : "NO");
35     }
36     return 0;
37 }
View Code

 

F. GukiZ Height

Solved.

题意:$f_i = f_{i - 1} + a_{(i - 1) \% n +1}, g_i = h - \frac{i \cdot (i + 1)}{2}, 求最小的i 使得 f_i >= g_i$

思路:枚举每个余数, 那么分为周期为0和周期>=1, 对于后面一种情况, 二分周期。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long 
 5 #define N 100010
 6 int n;
 7 ll h, a[N];
 8 ll sum[N];
 9 
10 bool check(ll x, int remind)
11 {
12     ll day = x * n + remind;
13     return h - (day * (day + 1)) / 2 <= sum[n] * x + sum[remind];
14 }
15 
16 int main()
17 {
18     while (scanf("%d%lld", &n, &h) != EOF)
19     {
20         sum[0] = 0;
21         for (int i = 1; i <= n; ++i) scanf("%lld", a + i);
22         for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i];
23         ll ans = (ll)1e18; 
24         for (int i = 1; i <= n; ++i) if(sum[i] >= h - (i * (i + 1) / 2)) ans = min(ans, 1ll * i);
25         for (int i = 1; i <= n; ++i)
26         {
27             ll l = 0, r = (2e9 + 10) / n, res = -1;
28             while (r - l >= 0)
29             {
30                 ll mid = (l + r) >> 1;
31 //                cout << i << " " << mid << endl;
32                 if (check(mid, i))
33                 {
34                     r = mid - 1;
35                     res = mid;
36                 }
37                 else
38                     l = mid + 1;
39             }
40 //            cout << i << " " << res << endl;
41             if (res != -1) 
42                 ans = min(ans, res * n + i); 
43         }
44         printf("%lld\n", ans);
45     }
46     return 0;
47 }
View Code

 

I. Prime Moving

Solved.

题意:将素数$a$通过某系列变化得到素数$b$, 每次变化可以加上或减去一个素数, 同时结果要求是素数。

思路:将2作为中间点, 各种分类

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 
  7 const int S = 10;
  8 
  9 ll mult_mod(ll a, ll b, ll c)
 10 {
 11     a %= c;
 12     b %= c;
 13     ll ret = 0;
 14     ll tmp = a;
 15     while(b)
 16     {
 17         if(b & 1)
 18         {
 19             ret += tmp;
 20             if(ret > c) ret -= c;
 21         }
 22         tmp <<= 1;
 23         if(tmp > c) tmp -= c;
 24         b >>= 1;
 25     }
 26     return ret;
 27 }
 28 
 29 ll pow_mod(ll a, ll n, ll mod)
 30 {
 31     ll ret = 1;
 32     ll tmp = a % mod;
 33     while(n)
 34     {
 35         if(n & 1) ret = mult_mod(ret, tmp, mod);
 36         tmp = mult_mod(tmp, tmp, mod);
 37         n >>= 1;
 38     }
 39     return ret;
 40 }
 41 
 42 bool check(ll a, ll n, ll x, ll t)
 43 {
 44     ll ret = pow_mod(a, x, n);
 45     ll last = ret;
 46     for(int i = 1; i <= t; ++i)
 47     {
 48         ret = mult_mod(ret, ret, n);
 49         if(ret == 1 && last != 1 && last != n - 1) return true;
 50         last = ret;
 51     }
 52     if(ret != 1) return true;
 53     else return false;
 54 }
 55 
 56 bool is_Prime(ll n)
 57 {
 58     if(n < 2) return false;
 59     if(n == 2) return true;
 60     if((n & 1) == 0) return false;
 61     ll x = n - 1;
 62     ll t = 0;
 63     while((x & 1) == 0) { x >>= 1; ++t; }
 64     srand(time(NULL));
 65     for(int i = 0; i < S; ++i)
 66     {
 67         ll a = rand() % (n - 1) + 1;
 68         if(check(a, n, x, t)) return false;
 69     }
 70     return true;
 71 }
 72 
 73 ll a, b;
 74 
 75 void solve()
 76 {
 77     if(a == 2)
 78     {
 79         if(is_Prime(b - 2))
 80         {
 81             printf("%lld->%lld\n", a, b);
 82             return ;
 83         }
 84         if(is_Prime(b + 2)) 
 85         {
 86             printf("%lld->%lld->%lld\n", a, b + 2, b);
 87             return ;
 88         }
 89     }
 90     else
 91     {
 92         if(b == a + 2)
 93         {
 94             printf("%lld->%lld\n", a, b);
 95             return ;
 96         }
 97         if(b == a + 4 && is_Prime(a + 2))
 98         {
 99             if(is_Prime(a - 2) && is_Prime(b - 2))
100             {
101                 puts("Poor Benny");
102                 return ;
103             }
104             else
105             {
106                 printf("%lld->%lld->%lld\n", a, a + 2, b);
107                 return ;
108             }
109         }
110         if(is_Prime(a - 2))
111         {
112             if(is_Prime(b - 2))
113             {
114                 printf("%lld->%lld->%lld\n", a, 2ll, b);
115                 return ;
116             }
117             if(is_Prime(b + 2))
118             {
119                 if(is_Prime(a + 2) && is_Prime(b - 2))
120                 {
121                     puts("Poor Benny");
122                     return ;    
123                 }
124                 else
125                 {
126                     printf("%lld->%lld->%lld->%lld\n", a, 2ll, b + 2, b);
127                     return ;
128                 }
129             }
130         }
131         if(is_Prime(a + 2))
132         {
133             if(is_Prime(b - 2))
134             {
135                 printf("%lld->%lld->%lld->%lld\n", a, a + 2, 2ll, b);
136                 return ;
137             }
138             if(is_Prime(b + 2))
139             {
140                 printf("%lld->%lld->%lld->%lld->%lld\n", a, a + 2, 2ll, b + 2, b);
141                 return ;
142             }
143         }
144     }
145     puts("Unlucky Benny");
146 }
147 
148 int main()
149 {
150     while(~scanf("%lld %lld", &a, &b))
151     {
152         solve();
153     }
154     return 0;
155 }
View Code

 

J. Valentina and the Gift Tree

Upsolved

题意:给出一棵树,询问$a -> b的简单路径上组成的序列的最大子段和$

思路:把一条简单路径拆成两条链,单独处理,一条链上用树链剖分处理,合并的时候注意左右端点怎么接

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define ll long long
  5 #define N 100010
  6 #define D 20
  7 #define INF 0x3f3f3f3f3f3f3f3f
  8 int n, q, g[N];
  9 vector <int> G[N];
 10 
 11 int sze[N], top[N], fa[D][N], son[N], p[N], fp[N], deep[N], cnt; 
 12 void DFS(int u)
 13 {
 14     sze[u] = 1; 
 15     for (int i = 1; i < D; ++i)
 16         fa[i][u] = fa[i - 1][fa[i - 1][u]]; 
 17     for (auto v : G[u]) if (v != fa[0][u])
 18     {
 19         fa[0][v] = u;  
 20         deep[v] = deep[u] + 1; 
 21         DFS(v);
 22         sze[u] += sze[v];
 23         if (!son[u] || sze[v] > sze[son[u]]) son[u] = v; 
 24     }
 25 }
 26 
 27 void gettop(int u, int sp)
 28 {
 29     top[u] = sp;
 30     p[u] = ++cnt;
 31     fp[cnt] = u;
 32     if (!son[u]) return;
 33     gettop(son[u], sp);
 34     for (auto v : G[u]) if (v != fa[0][u] && v != son[u])
 35         gettop(v, v);
 36 } 
 37 
 38 namespace SEG
 39 {
 40     struct node
 41     {
 42         ll lmax, rmax, Max, sum;
 43         node () {}
 44         void init()
 45         {
 46             lmax = rmax = Max = sum = -INF; 
 47         }
 48         node operator + (const node &other) const
 49         {
 50             node res; res.init();
 51             if (lmax == -INF || rmax == -INF)
 52                 return other; 
 53             if (other.lmax == -INF || other.rmax == -INF) 
 54                 return *this; 
 55             res.sum = sum + other.sum;
 56             res.lmax = max(lmax, sum + other.lmax);
 57             res.rmax = max(other.rmax, other.sum + rmax);
 58             res.Max = max(Max, other.Max);  
 59             res.Max = max(res.Max, rmax + other.lmax); 
 60             return res;
 61         }
 62     }a[N << 2], ans[2], tmp; 
 63     void build(int id, int l, int r)
 64     {
 65         a[id].init();
 66         if (l == r)
 67         {
 68             a[id].lmax = a[id].rmax = a[id].sum = a[id].Max = g[fp[l]];   
 69             return;
 70         }
 71         int mid = (l + r) >> 1;
 72         build(id << 1, l, mid);
 73         build(id << 1 | 1, mid + 1, r);
 74         a[id] = a[id << 1] + a[id << 1 | 1];
 75     }
 76     void query(int id, int l, int r, int ql, int qr)
 77     {
 78         if (qr < ql || ql <= 0 || qr <= 0) return; 
 79         if (l >= ql && r <= qr) 
 80         {
 81             tmp = tmp + a[id];
 82             return; 
 83         }
 84         int mid = (l + r) >> 1;
 85         if (ql <= mid) query(id << 1, l, mid, ql, qr);
 86         if (qr > mid) query(id << 1 | 1, mid + 1, r, ql, qr); 
 87     }
 88 }
 89 
 90 int lca(int u, int v)
 91 {
 92     while (top[u] != top[v])
 93     {
 94         if (deep[top[u]] < deep[top[v]]) swap(u, v);
 95         u = fa[0][top[u]];
 96     }
 97     if (deep[u] > deep[v]) swap(u, v);
 98     return u;
 99 }
100 
101 int kth(int u, int k)
102 {
103     for (int i = 0; i < D; ++i) 
104         if ((k >> i) & 1)
105             u = fa[i][u]; 
106     return u; 
107 }
108 
109 void query(int u, int v, int vis)
110 {
111     SEG::ans[vis].init();
112     while (top[u] != top[v])
113     {
114         if (deep[top[u]] < deep[top[v]]) swap(u, v);
115         SEG::tmp.init();  
116         SEG::query(1, 1, n, p[top[u]], p[u]);
117         SEG::ans[vis] = SEG::tmp + SEG::ans[vis];
118         u = fa[0][top[u]];
119     }
120     if (deep[u] > deep[v]) swap(u, v); 
121     SEG::tmp.init();
122     SEG::query(1, 1, n, p[u], p[v]);
123     SEG::ans[vis] = SEG::tmp + SEG::ans[vis];
124 }
125 
126 int main()
127 {
128     while (scanf("%d", &n) != EOF)  
129     {
130         for (int i = 1; i <= n; ++i) G[i].clear();
131         memset(son, 0, sizeof son); cnt = 0; deep[1] = 0;
132         for (int i = 1, u, v; i < n; ++i)
133         {
134             scanf("%d%d", &u, &v);
135             G[u].push_back(v);
136             G[v].push_back(u);
137         }
138         for (int i = 1; i <= n; ++i) scanf("%d", g + i);
139         deep[1] = 0; fa[0][1] = 0;
140         DFS(1); gettop(1, 1); SEG::build(1, 1, n);
141         //if (n == 10) return 0;
142         scanf("%d", &q); 
143         int a, b;
144         while (q--)
145         {
146             scanf("%d%d", &a, &b);
147             if (deep[a] > deep[b]) swap(a, b);
148             int Lca = lca(a, b);
149             if (a == Lca) 
150                 query(a, b, 0); 
151             else
152             {
153                 query(Lca, a, 0);
154                 query(kth(b, deep[b] - deep[Lca] - 1), b, 1);
155                 swap(SEG::ans[0].lmax, SEG::ans[0].rmax);
156                 SEG::ans[0] = SEG::ans[0] + SEG::ans[1];
157             }
158             printf("%lld\n", SEG::ans[0].Max); 
159         }
160     }
161     return 0;
162 }
View Code

 

LCA

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 
  7 const ll MOD = 1e9 + 7;
  8 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
  9 const int maxn = 1e5 + 10;
 10 
 11 const int DEG = 20;
 12 
 13 struct Edge {
 14     int to, nxt;
 15     Edge() {}
 16     Edge(int to, int nxt) :to(to), nxt(nxt) {}
 17 }edge[maxn << 1];
 18 
 19 struct node {
 20     ll lmax, rmax, ans, sum;
 21     node() 
 22     {
 23         sum = 0;
 24         lmax = rmax = ans = -INFLL;
 25     }
 26     node(ll tmp)
 27     {
 28         lmax = rmax = ans = sum = tmp;
 29     }
 30     node operator + (const node &other) const
 31     {
 32         node res;
 33         res.sum = sum + other.sum;
 34         res.lmax = max(lmax, sum + other.lmax);
 35         res.rmax = max(other.rmax, other.sum + rmax);
 36         res.ans = max(max(ans, other.ans), rmax + other.lmax);
 37         return res;
 38     }
 39 };
 40 
 41 int n, m;
 42 ll arr[maxn];
 43 int head[maxn], tot;
 44 node res[maxn][DEG];
 45 int fa[maxn][DEG];
 46 int deg[maxn];
 47 
 48 void Init()
 49 {
 50     tot = 0;
 51     memset(fa, -1, sizeof fa);
 52     memset(head, -1, sizeof head);
 53 }
 54 
 55 void addedge(int u, int v)
 56 {
 57     edge[tot] = Edge(v, head[u]); head[u] = tot++;
 58     edge[tot] = Edge(u, head[v]); head[v] = tot++;
 59     
 60 }
 61 
 62 void BFS(int root)
 63 {
 64     queue<int>q;
 65     deg[root] = 0;
 66     res[root][0] = node(arr[root]);
 67     fa[root][0] = root;
 68     q.push(root);
 69     while (!q.empty())
 70     {
 71         int tmp = q.front();
 72         q.pop();
 73         for (int i = 1; i < DEG; ++i)
 74         {
 75             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
 76             res[tmp][i] = res[tmp][i - 1] + res[fa[tmp][i - 1]][i - 1];
 77         }
 78         for (int i = head[tmp]; ~i; i = edge[i].nxt)
 79         {
 80             int v = edge[i].to;
 81             if (v == fa[tmp][0]) continue;
 82             deg[v] = deg[tmp] + 1;
 83             fa[v][0] = tmp;
 84             res[v][0] = node(arr[v]);
 85             q.push(v);
 86         }
 87     }
 88 }
 89 
 90 node LCA(int u, int v)
 91 {
 92     if (deg[u] > deg[v]) swap(u, v);
 93     int hu = deg[u], hv = deg[v];
 94     int tu = u, tv = v;
 95     node ansu, ansv;
 96     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
 97     {
 98         if (det & 1)
 99         {
100             ansv = ansv + res[tv][i];
101             tv = fa[tv][i];
102         }
103     }
104     for (int i = DEG - 1; i >= 0; --i)
105     {
106         if (fa[tu][i] == fa[tv][i]) continue;
107         ansu = ansu + res[tu][i];
108         ansv = ansv + res[tv][i];
109         tu = fa[tu][i];
110         tv = fa[tv][i];
111     }
112     while (tu != tv)
113     {
114         ansu = ansu + res[tu][0];
115         ansv = ansv + res[tv][0];
116         tu = fa[tu][0];
117         tv = fa[tv][0];
118     }
119     swap(ansv.lmax, ansv.rmax);
120     return ansu + res[tu][0] + ansv;
121 }
122 
123 void RUN()
124 {
125     while (~scanf("%d", &n))
126     {
127         Init();
128         for (int i = 1, u, v; i < n; ++i)
129         {
130             scanf("%d %d", &u, &v);
131             addedge(u, v);
132         }
133         for (int i = 1; i <= n; ++i) scanf("%lld", arr + i);
134         BFS(1); 
135         int q;
136         scanf("%d", &q);
137         for (int qq = 1, u, v; qq <= q; ++qq)
138         {
139             scanf("%d %d", &u, &v);
140             printf("%lld\n", LCA(u, v).ans);
141         }
142     }
143 }
144 
145 int main()
146 {
147 #ifdef LOCAL_JUDGE
148     freopen("Text.txt", "r", stdin);
149 #endif // LOCAL_JUDGE
150 
151     RUN();
152 
153 #ifdef LOCAL_JUDGE
154     fclose(stdin);
155 #endif // LOCAL_JUDGE
156     return 0;
157 }
View Code

 

posted @ 2019-02-27 20:09  Dup4  阅读(244)  评论(0编辑  收藏  举报