2018 HDU多校第三场赛后补题

从易到难来写吧,其中题意有些直接摘了Claris的,数据范围是就不标了。
如果需要可以去hdu题库里找。题号是6319 ~ 6331。

L. Visual Cube

题意:

在画布上画一个三维立方体。

题解:

模拟即可。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int a, b, c, R, C;
  4. char g[505][505];
  5. int main () {
  6. int T; cin >> T;
  7. for ( ; T; --T) {
  8. cin >> a >> b >> c;
  9. R = c * 2 + b * 2 + 1;
  10. C = a * 2 + b * 2 + 1;
  11. memset(g, '.', sizeof g);
  12. for (int i = R; i >= R - c * 2; i -= 2) {
  13. for (int j = 1; j <= a; ++j) {
  14. g[i][j * 2 - 1] = '+';
  15. g[i][j * 2] = '-';
  16. }
  17. g[i][a * 2 + 1] = '+';
  18. if (i == R - c * 2) continue;
  19. for (int j = 1; j <= a; ++j) {
  20. g[i - 1][j * 2 - 1] = '|';
  21. }
  22. g[i - 1][a * 2 + 1] = '|';
  23. }
  24. int ed = R, st = R - c * 2;
  25. for (int j = a * 2 + 1; j <= C; ++j) {
  26. int x = j - (a * 2);
  27. if (x & 1) {
  28. for (int i = st; i <= ed; ++i) {
  29. int y = ed - i;
  30. if (y & 1) g[i][j] = '|';
  31. else g[i][j] = '+';
  32. }
  33. } else {
  34. for (int i = st; i <= ed; ++i) {
  35. int y = ed - i;
  36. if (y & 1) g[i][j] = '.';
  37. else g[i][j] = '/';
  38. }
  39. }
  40. --ed, --st;
  41. }
  42. ed = b * 2 + 1, st = 1;
  43. for (int j = 1; j <= a * 2; ++j) {
  44. int x = j;
  45. if (x & 1) {
  46. for (int i = ed; i >= st; --i) {
  47. int y = i - st;
  48. if (y & 1) g[i][j + ed - i] = '/';
  49. else g[i][j + ed - i] = '+';
  50. }
  51. } else {
  52. for (int i = ed; i >= st; --i) {
  53. int y = i - st;
  54. if (y & 1) ;
  55. else g[i][j + ed - i] = '-';
  56. }
  57. }
  58. }
  59. for (int i = 1; i <= R; ++i) {
  60. for (int j = 1; j <= C; ++j) printf("%c", g[i][j]);
  61. puts("");
  62. }
  63. }
  64. return 0;
  65. }

D. Euler Function

题意:

求第\(n\)个使得\(\varphi(k)\)为合数的\(k\)。

题解:

其实应该会有尝试,就是\(n\)到一定大小\(\varphi(k)\)都是大于\(2\)的偶数,同时也是合数。其实找一下规律可以发现只有\(k = 1, 2, 3, 6\)时\(\varphi(k)\)为质数。证明在Claris的题解里有写。

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int main () {
  4. int T,n;
  5. scanf("%d",&T);
  6. while (T--) {
  7. scanf("%d",&n);
  8. if (n==1) printf("5\n");
  9. else printf("%d\n",5+n);
  10. }
  11. return 0;
  12. }

F. Grab The Tree

题意:

给定一棵\(n\)个点的树,每个点有权值。两个人玩游戏,先手需要占领若干不相邻的点,然后后手占领剩下所有点。每个人的得分为占领的点权异或和,分高的获胜。问最优策略下游戏的结果。

题解:

设\(sum\)为所有点权的异或和,\(A\)为先手得分,\(B\)为后手得分。
若\(sum=0\),则 \(A=B\),怎样都是平局。
否则考虑先手可以将原图分成两块,每一块里面的点都不相邻,然后取异或和较大的那块就好了,所以此时先手必胜。

代码:

  1. #include<bits/stdc++.h>
  2. #define N 100010
  3. using namespace std;
  4. int main () {
  5. int T,n,u,v,w;
  6. scanf("%d",&T);
  7. while (T--) {
  8. int sum=0;
  9. scanf("%d",&n);
  10. for(int i=1; i<=n; ++i) scanf("%d",&w),sum^=w;
  11. for(int i=1; i<n; ++i) scanf("%d%d",&u,&v);
  12. if (sum==0) printf("D\n"); else printf("Q\n");
  13. }
  14. return 0;
  15. }

C. Dynamic Graph Matching

题意:

给定一个n个点的无向图,\(m\)次加边或者删边操作。
在每次操作后统计有多少个匹配包含\(k = 1, 2, ...,\frac n 2\)条边。
其中匹配是指不相交的边集。

题解:

设 f[i][S] 表示前i次操作,匹配点集为S的方案数。
设当前边的两个端点为\(x,y\)。
对于加边,显然有\(f[i][S]=f[i-1][S]+f[i-1][S-x-y]。\)
其实,也可以直接省略第一维,执行\(f[S]+=f[S-x-y]\)。正确性是显然的。
对于删边,由于前面加边的顺序无所谓,所以我们不妨设我们删除的正是上一次加入的边(为了方便理解)。
这样,我们执行的就是一个你操作罢了:\(f[S]-=f[S-x-y]\)。

代码:

  1. #pragma GCC optimize(2)
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. const int mo = 1e9 + 7, N = 11;
  5. int n, m, bc[1 << N], f[1 << N], ans[N]; char op[5];
  6. int bitcnt (int x) {
  7. return x ? bitcnt(x >> 1) + (x & 1) : 0;
  8. }
  9. int main () {
  10. int T; cin >> T;
  11. for (int i = 0; i < (1 << N); ++i) bc[i] = bitcnt(i);
  12. for ( ; T; --T) {
  13. cin >> n >> m, f[0] = 1;
  14. for (int s = 1; s < (1 << n); ++s) f[s] = 0;
  15. for (int i = 1, x, y; i <= m; ++i) {
  16. scanf("%s%d%d", op, &x, &y), --x, --y;
  17. if (op[0] == '+') {
  18. for (int s = 0, t; s < (1 << n); ++s) {
  19. if ((s >> x & 1) || (s >> y & 1)) continue;
  20. t = s | 1 << x | 1 << y;
  21. f[t] += f[s];
  22. if (f[t] >= mo) f[t] -= mo;
  23. }
  24. } else {
  25. for (int s = (1 << n) - 1, t; ~s; --s) {
  26. if ((s >> x & 1) || (s >> y & 1)) continue;
  27. t = s | 1 << x | 1 << y;
  28. f[t] -= f[s];
  29. if (f[t] < 0) f[t] += mo;
  30. }
  31. }
  32. for (int i = 1; i <= (n >> 1); ++i) ans[i] = 0;
  33. for (int s = 1, t; s < (1 << n); ++s) {
  34. t = bc[s]; if (t & 1) continue; else t >>= 1;
  35. ans[t] += f[s];
  36. if (ans[t] >= mo) ans[t] -= mo;
  37. }
  38. for (int i = 1; i <= (n >> 1); ++i) {
  39. printf("%d%c", ans[i], i < (n >> 1) ? ' ' : '\n');
  40. }
  41. }
  42. }
  43. return 0;
  44. }

G. Interstellar Travel

题意:

给定平面上\(n\)个点,起点横坐标最小,终点横坐标最大,所有点都在第一象限内。(包括坐标轴)
每次可以飞到一个横坐标严格更大的点,代价为两个坐标的叉积。
求起点到终点总代价最小的飞行路线,并输出字典序最小的路线。

题解:

因为叉积的几何意义就是有向平行四边形的面积的,然后根据题目给出的性质,很快就能反应过来,只需要维护一个凸包就好了(因为这个凸包面积最大,并且是负的,对应最小代价)。
注意会有重点的问题。

代码:

  1. #include <bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. const int N = 200005;
  5. int n, top;
  6. struct point {
  7. int x, y, i;
  8. point () {}
  9. point (int _x,int _y,int _i = 0) :
  10. x(_x), y(_y), i(_i) {}
  11. } a[N], s[N];
  12. point operator - (point u, point v) {
  13. return point(u.x - v.x, u.y - v.y, u.i);
  14. }
  15. bool cmp (point u, point v) {
  16. ll t = 1ll * u.x * v.y - 1ll * u.y * v.x;
  17. return t == 0 ? (u.x == v.x ? u.i < v.i: u.x < v.x) : t < 0;
  18. }
  19. bool cmp2 (point u, point v) {
  20. ll t = 1ll * u.x * v.y - 1ll * u.y * v.x;
  21. return t == 0 ? u.i < v.i : t < 0;
  22. }
  23. void solve () {
  24. s[top = 1] = a[1];
  25. for (int i = 2; i <= n; ++i) {
  26. if (a[i].x == a[i - 1].x && a[i].y == a[i - 1].y) continue;
  27. while (top >= 2 && cmp2(a[i] - s[top - 1], s[top] - s[top - 1])) --top;
  28. s[++top] = a[i];
  29. }
  30. }
  31. int main () {
  32. int T; cin >> T;
  33. for ( ; T; --T) {
  34. cin >> n;
  35. for (int i = 1; i <= n; ++i) {
  36. scanf("%d%d", &a[i].x, &a[i].y);
  37. a[i].i = i;
  38. }
  39. sort(a + 2, a + n, cmp);
  40. solve();
  41. for (int i = 1; i <= top; ++i) {
  42. printf("%d%c", s[i].i, i < top ? ' ' : '\n');
  43. }
  44. }
  45. return 0;
  46. }

A. Ascending Rating

题意:

给定一个序列\(a[1..n]\),对于每个长度为\(m\)的连续子区间,求出区间\(a\)的最大值以及从左往右扫描该区间时\(a\)的最大值的变化次数。

题解:

这题反正来似乎比较容易。。
考虑导致维护一个单调递减的单调队列,其中队列大小\(size\)就是当前区间最大值的变化次数,队列中最后一个元素就是区间最大值。具体想一想就好了。其实我是不会打单调数据结构的

代码:

  1. #include <bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. const int N = 10000005;
  5. int n, m, k, p, q, r, mo, a[N];
  6. int h, t, Q[N];
  7. ll A, B;
  8. int read () {
  9. int x = 0; char ch = getchar();
  10. for ( ; ch < '0' || ch > '9'; ch = getchar());
  11. for ( ; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
  12. return x;
  13. }
  14. int main () {
  15. int T; cin >> T;
  16. for ( ; T; --T) {
  17. cin >> n >> m >> k >> p >> q >> r >> mo;
  18. for (int i = 1; i <= k; ++i) a[i] = read();
  19. for (int i = k + 1; i <= n; ++i) a[i] = (1ll * p * a[i - 1] + 1ll * q * i + r) % mo;
  20. h = 0, t = 1, A = B = 0;
  21. for (int i = n; i >= n - m + 1; --i) {
  22. if (a[i] < a[Q[h]]) Q[++h] = i;
  23. else {
  24. for ( ; t <= h && a[i] >= a[Q[h]]; ) --h;
  25. Q[++h] = i;
  26. }
  27. }
  28. A += a[Q[t]] ^ (n - m + 1);
  29. B += (h - t + 1) ^ (n - m + 1);
  30. for (int i = n - m; i; --i) {
  31. if (Q[t] == i + m) ++t;
  32. if (a[i] < a[Q[h]]) Q[++h] = i;
  33. else {
  34. for ( ; t <= h && a[i] >= a[Q[h]]; ) --h;
  35. Q[++h] = i;
  36. }
  37. A += a[Q[t]] ^ i;
  38. B += (h - t + 1) ^ i;
  39. }
  40. cout << A << " " << B << endl;
  41. }
  42. return 0;
  43. }

I. Random Sequence

题意:

给定一个正整数序列\(a[1..n]\)和一个\(v\)数组,每个数在\([1, m]\)之间,有些数已知,有些数未知。
求未知数随机填的情况下以下值的期望:
\[ \begin{eqnarray*} \prod_{i=1}^{n-3} v[\gcd(a_i,a_{i+1},a_{i+2},a_{i+3})] \end{eqnarray*} \]

题解:

观察下这题的数据范围,发现可以写个dp。
\(f[i][x][y][z]\)表示将位置\(1~i\)(可能进行的)填数后,\(a[i]=x,gcd(a[i],a[i-1])=y,gcd(a[i],a[i-1],a[i-2])=z\)的期望答案(即套上连乘符号的)。
则我们可以很轻松知道转移方程。
但要注意的是这个连乘符号可能导致算期望的式子和我们平时做到的略有不同。总之,是有这样的式子:
\[ E[s] = V[s] * \begin{eqnarray*} \sum_{pre(s)}^{} E[pre]*pro[pre,s] \end{eqnarray*} \]
但别以为这样就完事了。
注意到这样会MLE,所以你可以选择开滚动数组。
然后你又被卡TLE了。注意到对于一个合法状态\((x,y,z)\),满足\(z|y\)且\(y|x\)。利用这个就可以简化状态数。
然后你就稳了。注意前三项是不计贡献的。

代码:

  1. #pragma GCC optimize(2)
  2. #include <bits/stdc++.h>
  3. #define ll long long
  4. using namespace std;
  5. const int N = 105, mo = 1e9 + 7;
  6. int n, m, g[N][N], inv[N], a[N], v[N];
  7. int f[2][N][N][N];
  8. int ksm (int b, int p) {
  9. if (p < 2) return p ? b : 1;
  10. int t = ksm(b, p >> 1); t = 1ll * t * t % mo;
  11. return p & 1 ? 1ll * t * b % mo : t;
  12. }
  13. int main () {
  14. int T; cin >> T;
  15. for (int i = 0; i <= 100; ++i) g[0][i] = g[i][0] = i;
  16. for (int i = 1; i <= 100; ++i)
  17. for (int j = 1; j <= 100; ++j) g[i][j] = __gcd(i, j);
  18. for (int i = 1; i <= 100; ++i) inv[i] = ksm(i, mo - 2);
  19. for ( ; T; --T) {
  20. cin >> n >> m;
  21. for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
  22. for (int i = 1; i <= m; ++i) scanf("%d", &v[i]);
  23. memset(f, 0, sizeof f);
  24. int nx, ny, nz, tmp;
  25. for (int z = 1; z <= m; ++z)
  26. for (int y = 1; y <= m; ++y)
  27. for (int x = 1; x <= m; ++x) {
  28. if (a[1] && a[1] != z) continue;
  29. if (a[2] && a[2] != y) continue;
  30. if (a[3] && a[3] != x) continue;
  31. nx = x, ny = g[x][y], nz = g[ny][z];
  32. tmp = 1;
  33. if (!a[1]) tmp = 1ll * tmp * inv[m] % mo;
  34. if (!a[2]) tmp = 1ll * tmp * inv[m] % mo;
  35. if (!a[3]) tmp = 1ll * tmp * inv[m] % mo;
  36. f[1][nx][ny][nz] += tmp;
  37. if (f[1][nx][ny][nz] >= mo) f[1][nx][ny][nz] -= mo;
  38. }
  39. for (int i = 3, c; i <= n; ++i) {
  40. c = i & 1, memset(f[c ^ 1], 0, sizeof f[c ^ 1]);
  41. for (int z = 1; z <= m; ++z)
  42. for (int y = z; y <= m; y += z)
  43. for (int x = y; x <= m; x += y) if (f[c][x][y][z]) {
  44. if (a[i + 1]) {
  45. nx = a[i + 1], ny = g[x][a[i + 1]], nz = g[y][a[i + 1]];
  46. f[c ^ 1][nx][ny][nz] += 1ll * f[c][x][y][z] * v[g[a[i + 1]][z]] % mo;
  47. if (f[c ^ 1][nx][ny][nz] >= mo) f[c ^ 1][nx][ny][nz] -= mo;
  48. continue;
  49. }
  50. for (int j = 1; j <= m; ++j) {
  51. nx = j, ny = g[x][j], nz = g[y][j];
  52. f[c ^ 1][nx][ny][nz] += 1ll * f[c][x][y][z] * v[g[j][z]] % mo * inv[m] % mo;
  53. if (f[c ^ 1][nx][ny][nz] >= mo) f[c ^ 1][nx][ny][nz] -= mo;
  54. }
  55. }
  56. }
  57. int ans = 0;
  58. for (int z = 1; z <= m; ++z)
  59. for (int y = z; y <= m; y += z)
  60. for (int x = y; x <= m; x += y) ans = (ans + f[n & 1][x][y][z]) % mo;
  61. cout << ans << endl;
  62. }
  63. return 0;
  64. }

M. Walking Plan

题意:

给定一个\(n\)个点,\(m\)条边的有向图,\(q\)次询问\(s\)到\(t\)经过至少\(k\)条边的最短路。

题解:

注意观察数据范围。
显然可以预处理出\(f[k][i][j]\)表示i经过恰好k条边到达j的最短路。
转移方程:\(f[k][i][j]=min(f[k−1][i][x]+w[x][j])\)。(看f[k]长得很像个矩阵,不过这题并不用这个性质)
当然你可以选择用\(O(n^3 * 10000)\)的时间预处理,然后愉快地gg了。
当然还有更好的选择。我们来分块!
我们预处理出\(f[k][i][j]\)表示i经过恰好k条边到达j的最短路,其中\(0<=k<=100\)。
再预处理出\(g[k][i][j]\)表示i经过恰好100k条边到达j的最短路,其中\(0<=k<=100\)。
对于一个询问,设\(A = k / 100\),\(B\) \(=\) \(k\) \(mod\) \(100\)。
则我们枚举中间点,\(ans=min(a[A][s][x]+b[B][x][t])\)。
这样是不是就好了?
错!
题目中要求的是至少经过\(k\)条边,而非恰好。
所以我们在\(b\)数组中做点手脚。其实就是先跑出原图的最短路,然后以“恰当的方式”更新\(b\)数组就好了。
这个恰当的方式可以参考一下具体实现。
复杂度是\(O(n^3 \sqrt k+ nq)\)。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 55, K = 10005, S = 105, inf = 0x3f3f3f3f;
  4. int n, m, q, ans, g[N][N], f[N][N], A[S][N][N], B[S][N][N];
  5. int main () {
  6. int T; cin >> T;
  7. for ( ; T; --T) {
  8. cin >> n >> m;
  9. memset(g, 0x3f, sizeof g);
  10. memset(A, 0x3f, sizeof A);
  11. memset(B, 0x3f, sizeof B);
  12. for (int i = 1, x, y, z; i <= m; ++i) {
  13. scanf("%d%d%d", &x, &y, &z);
  14. g[x][y] = min(g[x][y], z);
  15. B[1][x][y] = g[x][y];
  16. }
  17. for (int i = 1; i <= n; ++i)
  18. for (int j = 1; j <= n; ++j) A[0][i][j] = B[0][i][j] = i == j ? 0 : inf;
  19. for (int k = 2; k <= 100; ++k) {
  20. for (int i = 1; i <= n; ++i)
  21. for (int j = 1; j <= n; ++j)
  22. for (int x = 1; x <= n; ++x)
  23. B[k][i][j] = min(B[k][i][j], B[k - 1][i][x] + B[1][x][j]);
  24. }
  25. for (int i = 1; i <= n; ++i) {
  26. for (int j = 1; j <= n; ++j) A[1][i][j] = B[100][i][j];
  27. }
  28. for (int k = 2; k <= 100; ++k) {
  29. for (int i = 1; i <= n; ++i)
  30. for (int j = 1; j <= n; ++j)
  31. for (int x = 1; x <= n; ++x)
  32. A[k][i][j] = min(A[k][i][j], A[k - 1][i][x] + A[1][x][j]);
  33. }
  34. for (int i = 1; i <= n; i++) g[i][i] = 0;
  35. for (int x = 1; x <= n; ++x) {
  36. for (int i = 1; i <= n; ++i) {
  37. for (int j = 1; j <= n; ++j) g[i][j] = min(g[i][j], g[i][x] + g[x][j]);
  38. }
  39. }
  40. for (int k = 0; k <= 100; ++k) {
  41. for (int i = 1; i <= n; ++i)
  42. for (int j = 1; j <= n; ++j) f[i][j] = inf;
  43. for (int i = 1; i <= n; ++i)
  44. for (int j = 1; j <= n; ++j)
  45. for (int x = 1; x <= n; ++x) f[i][j] = min(f[i][j], B[k][i][x] + g[x][j]);
  46. for (int i = 1; i <= n; ++i)
  47. for (int j = 1; j <= n; ++j) B[k][i][j] = f[i][j];
  48. }
  49. cin >> q;
  50. for (int s, t, k, u, v; q; --q) {
  51. scanf("%d%d%d", &s, &t, &k), ans = inf;
  52. u = k / 100, v = k % 100;
  53. for (int i = 1; i <= n; ++i) {
  54. ans = min(ans, A[u][s][i] + B[v][i][t]);
  55. }
  56. if (ans >= inf) ans = -1;
  57. printf("%d\n", ans);
  58. }
  59. }
  60. return 0;
  61. }

H. Monster Hunter

题意:

给定一棵\(n\)个点的树,除\(1\)外每个点有一只怪兽,打败它需要先消耗\(a[i]\)点 HP,再恢复\(b[i]\)点 HP。
求从\(1\)号点出发按照最优策略打败所有怪兽一开始所需的最少HP(其中,过程中不能出现HP为负的情况)。

题解:

这题教会了我们从简单的情况思考。
假设没有“树”的限制,即没有定死的先后顺序。怎么办?
显然贪心。
将怪兽分成两类考虑:\(a<b\)和\(a>=b\)。其实这种贪心见到过不止一次
显然应该先打前一类,再打后一类。
前一类的显然是先打a小的。可以感性理解一下。其实很好证,时间关系,不证了。
后一类呢,稍微要想一想。我就拖一下Claris的证明吧:
对于\(a>=b\)的怪兽,考虑两只怪兽\(i\),\(j\)。
先打\(i\)再打\(j\): $HPmin=HP - a[i] + b[i] - a[j] $
先打\(j\)再打\(i\): $HPmin=HP - a[j] + b[j] - a[i] $
这样的话,我们必定会选择\(b\)大的先打。
再回头考虑原问题。设排好序后,顺序为\(p[1],p[2],...,p[n]\)
若\(p[1] = 1\),那么第一步打\(p[1]\)一定最优。
否则在打完\(p[1]\)的父亲\(fa\)后,紧接着打\(p[1]\)一定最优。直接合并它们。
剩下的是规模为\(n-1\)的子问题。
注意这里合并和快速搜索最优分别要用到并查集和堆。
复杂度是\(O(nlogn)\)的。

代码:

  1. #include <bits/stdc++.h>
  2. #define mp make_pair
  3. #define ll long long
  4. using namespace std;
  5. const int N = 100005;
  6. int n, P, a[N], b[N];
  7. int tot, lnk[N], nxt[N << 1], son[N << 1], fa[N];
  8. bool dead[N];
  9. struct mons {
  10. ll a, b; int i, t;
  11. mons () {}
  12. mons (ll _a, ll _b, int _i = 0,int _t = 0) :
  13. a(_a), b(_b), i(_i), t(_t) {}
  14. bool operator < (const mons &o) const {
  15. bool k1 = a < b, k2 = o.a < o.b;
  16. if (k1 != k2) return k1 < k2;
  17. else return a >= b ? b < o.b : a > o.a;
  18. }
  19. void operator += (const mons &o) {
  20. ll na = max(a, a - b + o.a), nb = - a + b - o.a + o.b + na;
  21. a = na, b = nb;
  22. }
  23. } m[N], cur;
  24. priority_queue <mons> q;
  25. int read () {
  26. int x = 0; char ch = getchar();
  27. for ( ; ch < '0' || ch > '9'; ch = getchar());
  28. for ( ; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48;
  29. return x;
  30. }
  31. void add (int x, int y) {
  32. nxt[++tot] = lnk[x], lnk[x] = tot, son[tot] = y;
  33. }
  34. void dfs (int x, int p) {
  35. fa[x] = p;
  36. for (int j = lnk[x]; j; j = nxt[j]) {
  37. if (son[j] == p) continue;
  38. dfs(son[j], x);
  39. }
  40. }
  41. int get (int x) {
  42. return dead[fa[x]] ? fa[x] = get(fa[x]) : fa[x];
  43. }
  44. int main () {
  45. for (int T = read(); T; --T) {
  46. n = read(), tot = 0;
  47. for (int i = 1; i <= n; ++i) lnk[i] = 0, dead[i] = 0;
  48. for (int i = 1; i <= n * 2; ++i) nxt[i] = 0;
  49. for ( ; !q.empty(); q.pop());
  50. m[1] = mons(0, 0, 1, 0);
  51. for (int i = 2; i <= n; ++i) {
  52. m[i].a = read(), m[i].b = read();
  53. m[i].i = i, m[i].t = 0, q.push(m[i]);
  54. }
  55. for (int i = 1, x, y; i < n; ++i) {
  56. x = read(), y = read();
  57. add(x, y), add(y, x);
  58. }
  59. dfs(1, 0), dead[1] = 0;
  60. for (int sec = 1; !q.empty(); ++sec) {
  61. cur = q.top(), q.pop();
  62. if (cur.t != m[cur.i].t || dead[cur.i]) continue;
  63. get(cur.i), dead[cur.i] = 1;
  64. P = get(cur.i);
  65. m[P] += m[cur.i], m[P].t = sec;
  66. if (P > 1) q.push(m[P]);
  67. }
  68. cout << max(0ll, m[1].a) << endl;
  69. }
  70. return 0;
  71. }

剩下的题可能有点难搞了。。

2018 HDU多校第三场赛后补题的更多相关文章

  1. 2018 HDU多校第四场赛后补题

    2018 HDU多校第四场赛后补题 自己学校出的毒瘤场..吃枣药丸 hdu中的题号是6332 - 6343. K. Expression in Memories 题意: 判断一个简化版的算术表达式是否 ...

  2. 2018年多校第三场第一题 A. Ascending Rating hdu6319

    比赛地址:http://acm.hdu.edu.cn/contests/contest_show.php?cid=804 题目编号:第一题 A. Ascending Rating  hdu6319 题 ...

  3. hdu 5317 RGCDQ (2015多校第三场第2题)素数打表+前缀和相减求后缀(DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5317 题意:F(x) 表示x的不同质因子的个数结果是求L,R区间中最大的gcd( F(i) , F(j ...

  4. hdu 5316 Magician(2015多校第三场第1题)线段树单点更新+区间合并

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5316 题意:给你n个点,m个操作,每次操作有3个整数t,a,b,t表示操作类型,当t=1时讲a点的值改 ...

  5. hdu多校第三场

    Problem D. Euler Function 思路:打表找找规律. #include<bits/stdc++.h> #define LL long long #define fi f ...

  6. HDU 多校 第三场 Find the answer

    这题是原来cf上的一道原题,不过对于有一些数据范围修改了,不过还是很好想的 题意:给定一个长度为N的数组,对于数组中的每个位置,满足当前和小于M所需要去掉的最小代价 分析:对于当前是否需要进行去掉一些 ...

  7. HDU 多校 第三场 Fansblog

    代码千万条,规范第一条 训练赛的时候打表找规律,发现答案是1/(st-pre-1)!,奈何用错了模板,一直TLE到比赛结束,一直以为是卡什么输入输出或者是两个素数相差太大导致复杂度过高,读入优化啥的都 ...

  8. hdu多校第三场 1007 (hdu6609) Find the answer 线段树

    题意: 给定一组数,共n个,第i次把第i个数扔进来,要求你删掉前i-1个数中的一些(不许删掉刚加进来这个数),使得前i个数相加的和小于m.问你对于每个i,最少需要删掉几个数字. 题解: 肯定是优先删大 ...

  9. hdu多校第三场 1006 (hdu6608) Fansblog Miller-Rabin素性检测

    题意: 给你一个1e9-1e14的质数P,让你找出这个质数的前一个质数Q,然后计算Q!mod P 题解: 1e14的数据范围pass掉一切素数筛法,考虑Miller-Rabin算法. 米勒拉宾算法是一 ...

随机推荐

  1. Cron表达式解析

    每一个域可出现的字符如下:Seconds:          可出现     ", - * /"     四个字符,有效范围为0-59的整数Minutes:          可出 ...

  2. python dict字典和set集合用法

    创建字典:键  值  key  value c = {'张三':59, '李四':60, '王五':100} #查 print(c['张三'])  #打印张三的成绩 #改 c['张三'] = 60 # ...

  3. ElasticSearch(十二)删除数据插件delete-by-query

    在ElasticSearch2.0之后的版本中没有默认的delete-by-query,想使用此命令需要安装这个插件. 首先需要进入ES的目录 [root@node122 elasticsearch] ...

  4. HttpRequest,HttpResponse,乱码,转发和重定向

    HttpServletRequest简介 Web服务器收到客户端的http请求,会针对每一次请求,创建一个用于代表请求的HttpServletRequest类型的request对象,并将"H ...

  5. xftp5和xshell的使用

    目的:实现windows和linux系统之间文件的传输 步骤:1)下载xshell5 百度搜索即可,直接下载安装 2)xshell5下载完成后与虚拟机链接成功 3)下载xftp5点击 然后跟据官方的指 ...

  6. Java实训作业1

    1.编写程序:声明一个整型变量a,并赋初值5,在程序中判断a是奇数还是偶数,然后输出判断的结果 2.编写程序:从键盘输入圆的半径,计算圆的面积并输出. 3.编写程序:实现一个数字加密器.运行时输入加密 ...

  7. Haystack

    什么是Haystack Haystack是django的开源全文搜索框架(全文检索不同于特定字段的模糊查询,使用全文检索的效率更高 ),该框架支持Solr,Elasticsearch,Whoosh,  ...

  8. xueping wang 记录2

    在使用easyui的tabs的时候, 标签页上的 可关闭 按钮 显示不出来? tabs的 closable:true 属性, 实际上是通过在 标签头 tabHeader 中的最后面, 添加一个超链接 ...

  9. 动态生成具有嵌套属性的linq选择(select)

    class SelectItem { public string Item { get; set; } } class SelectList { public int ID { get; set; } ...

  10. idea使用的小技巧总结

    1.需要一个快捷清爽的控制台? 下面这段配置是你需要的,在workspace.xml里面添加 <component name="RunDashboard"> <o ...