正睿20NOIp前冲刺day12

估分:60+20+30=110

实际:40+20+10=70

T1:

  写了个分治,是错的,正解不会证,没写

  如果只考虑朝上走,就是求出每个点可以走到的点,倍增。之后看往下走的一段。对于一条链,如果体力都是满的从两边开始走,那么复活的次数是一样的。因为这个等价于将整条序列分成尽量少的段,使得每一段之和都不小于k ,所以从两边开始贪心都是对的。所以可以找到拐下去的点之后,从下往上倍增。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 #define int long long
  8 
  9 const int N = 200010, M = 4010;
 10 
 11 int n, k, cnt;
 12 int len[N], dep[N], f[N][30], F[N][30], tot, ans;
 13 int h[N], num[N << 1], nex[N << 1], v[N << 1], dqx;
 14 
 15 void add(int a, int b, int c)
 16 {
 17     num[dqx] = b;
 18     v[dqx] = c;
 19     nex[dqx] = h[a];
 20     h[a] = dqx++;
 21 }
 22 
 23 void dfs1(int x, int pa)
 24 {
 25     dep[x] = dep[pa] + 1;
 26     for (int i = 0; i <= 19; i++) f[x][i + 1] = f[f[x][i]][i];
 27     for (int i = h[x]; ~i; i = nex[i]) 
 28     {
 29         int y = num[i];
 30         if (y == pa) continue;
 31         f[y][0] = x;
 32         len[y] = len[x] + v[i];
 33         dfs1(y, x);
 34     }
 35 }
 36 
 37 void dfs2(int x, int pa)
 38 {
 39     int tot = 0, t = x;
 40     for (int i = 20; ~i; i--)
 41     {
 42         if (len[x] - len[f[x][i]] < k - tot)
 43         {
 44             tot += len[x] - len[f[x][i]];
 45             x = f[x][i];
 46         }
 47     }
 48         
 49     F[t][0] = f[x][0], x = t;
 50     for (int i = 0; i <= 19; i++) F[x][i + 1] = F[F[x][i]][i];
 51     for (int i = h[x]; ~i; i = nex[i])
 52     {
 53         int j = num[i];
 54         if (j == pa) continue;
 55          dfs2(j, x);
 56     }
 57 }
 58 
 59 int LCA(int x, int y)
 60 {
 61     if (dep[x] < dep[y]) swap(x, y);
 62     for (int i = 20; ~i; i--)
 63     {
 64         if (dep[f[x][i]] >= dep[y]) x = f[x][i];
 65     }
 66     if (x == y) return x;
 67     for (int i = 20; ~i; i--)
 68     {
 69         if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
 70     }
 71     return f[x][0];
 72 }
 73 
 74 signed main()
 75 {
 76     scanf("%lld%lld", &n, &k);
 77 
 78     memset(h, -1, sizeof(h));
 79     for (int i = 1; i < n; i++) 
 80     {
 81         int x, y, z;
 82         scanf("%lld%lld%lld", &x, &y, &z);
 83         add(x, y, z), add(y, x, z);
 84     }
 85 
 86     dfs1(1, 0);
 87     dfs2(1, 0);
 88 
 89     int q;
 90     scanf("%d", &q);
 91     while (q--) 
 92     {
 93         int x, y;
 94         scanf("%lld%lld", &x, &y);
 95         int c = LCA(x, y);
 96         ans = tot = 0;
 97         for (int i = 20; i >= 0; i--)
 98         {
 99             if (dep[F[x][i]] >= dep[c])
100             {
101                 x = F[x][i], ans += (1 << i);
102             }
103         }
104 
105         tot += len[x] - len[c];
106         if (k - tot <= len[y] - len[c]) 
107         {
108             ans++, x = y;
109             for (int i = 20; i >= 0; i--) if (len[f[y][i]] - len[c] >= k - tot) y = f[y][i];
110             c = y;
111             for (int i = 20; i >= 0; i--)
112             {
113                 if (dep[F[x][i]] >= dep[c])
114                 {
115                     x = F[x][i];
116                     ans += (1 << i);
117                 }
118             }
119                 
120         }
121         printf("%lld\n", ans);
122     }
123 }
View Code

T2:

  20pts暴力

T3:

  写了个20pts的图论,错的

总结:

  这次代码到是没炸,但算法都没对,下次有啥思路直接写吧,这次的第一题就因为不会证没写所以没A掉

posted on 2020-10-27 17:43  ArrogHie  阅读(134)  评论(0编辑  收藏  举报