「NOIP 2015」运输计划

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「NOIP 2015」运输计划相关的知识,希望对你有一定的参考价值。

「题意」

  给 $n(\le 300000)$ 个点的树,经过每条边需要花费时间 $c$ 。

  有 $m(\le 300000)$ 个运输计划,将某条边变为虫洞,花费 $0$ 的时间,最小化最大花费时间。

「分析」

  二分最大花费时间 $x$ 。

  设 $S$ 为花费大于 $x$ 的路径的集合,$M$ 为路径花费减去 $x$ 的最大值。一条边权为 $c$ 的边可以变为虫洞,当且仅当属于 $S$ 中所有路径的并,且 $c \ge M$ 。

  通过树形 DP ,判断一条边是不是所有路径的并。

「实现」

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cctype>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <algorithm>
  8 using namespace std;
  9 #define F(i, a, b) for (register int i = (a), _b = (b); i <= _b; i++)
 10 #define D(i, a, b) for (register int i = (a), _b = (b); i >= _b; i--)
 11 #define fore(x) for (register int k = hd[x], v; k > 0; k = mp[k].nx) if ((v = mp[k].v) != par[x])
 12 
 13 const int S = 10000000;
 14 char s[S], *h = s+S, *t = h;
 15 inline char nchar(void) { if (h == t) fread(s, 1, S, stdin), h = s; return *h++; }
 16 inline int rd(void) {
 17     int f = 1; char c = nchar(); for (; !isdigit(c); c = nchar()) if (c == -) f = -1;
 18     int x = 0; for (; isdigit(c); c = nchar()) x = x*10+c-0; return x*f;
 19 }
 20 
 21 const int N = 300005;
 22 
 23 int n;
 24 struct E {
 25     int v, d, nx;
 26 }mp[2*N];
 27 int tot, hd[N];
 28 
 29 int dep[N], dis[N], w[N], par[N], siz[N], son[N];
 30 int top[N];
 31 
 32 void Son(int x) {
 33     siz[x] = 1;
 34     fore(x) {
 35         dep[v] = dep[x] + 1, dis[v] = dis[x] + mp[k].d, w[v] = mp[k].d, par[v] = x;
 36         Son(v);
 37         siz[x] += siz[v];
 38         if (siz[son[x]] < siz[v]) son[x] = v;
 39     }
 40 }
 41 void spl(int x, int anc) {
 42     top[x] = anc;
 43     if (son[x] > 0) spl(son[x], anc);
 44     fore(x) if (v != son[x])
 45         spl(v, v);
 46 }
 47 inline int LCA(int x, int y) {
 48     while (top[x] != top[y])
 49         dep[top[x]] > dep[top[y]] ? x = par[top[x]] : y = par[top[y]];
 50     return dep[x] <= dep[y] ? x : y;
 51 }
 52 
 53 int m, u[N], v[N], anc[N];
 54 int idx, d[N];
 55 
 56 void run(int x) {
 57     fore(x)
 58         run(v), d[x] += d[v];
 59 }
 60 int Deq(int x) {
 61     int Max = 0;
 62     idx = 0, memset(d, 0, sizeof d);
 63     F(i, 1, m) {
 64         int L = dis[u[i]] + dis[v[i]] - 2 * dis[anc[i]];
 65         if (L > x) idx++, d[u[i]]++, d[v[i]]++, d[anc[i]] -= 2, Max = max(Max, L-x);
 66     }
 67     run(1);
 68     F(i, 1, n) if (d[i] == idx && w[i] >= Max)
 69         return 1;
 70     return 0;
 71 }
 72 
 73 int main(void) {
 74     #ifndef ONLINE_JUDGE
 75         freopen("150.in", "r", stdin);
 76         freopen("150.out", "w", stdout);
 77     #endif
 78     
 79     n = rd(), m = rd();
 80     F(i, 1, n-1) {
 81         int x = rd(), y = rd(), d = rd();
 82         mp[++tot] = (E){y, d, hd[x]}, hd[x] = tot;
 83         mp[++tot] = (E){x, d, hd[y]}, hd[y] = tot;
 84     }
 85     
 86     Son(1);
 87     spl(1, 1);
 88     
 89     F(i, 1, m)
 90         u[i] = rd(), v[i] = rd(), anc[i] = LCA(u[i], v[i]);
 91     
 92     int l = 0, r = 300000 * 1000;
 93     while (l < r) {
 94         int x = (l + r) >> 1;
 95         Deq(x) ? r = x : l = x+1;
 96     }
 97     printf("%d\n", l);
 98     
 99     return 0;
100 }

 

以上是关于「NOIP 2015」运输计划的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2015 运输计划(二分+LCA+差分)

NOIP2015提高组运输计划

[NOIP2015提高组]运输计划

运输计划(题解)(Noip2015)

NOIp 2015 运输计划

noip2015运输计划