2093:【22CSPS提高组】数据传输(transmit)
时间限制: 3000 ms 内存限制: 524288 KB
提交数: 37 通过数: 6【题目描述】
小 C 正在设计计算机网络中的路由系统。
测试用的网络总共有 nn 台主机,依次编号为 11 ∼ nn。这 nn 台主机之间由 n−1n−1 根网线连接,第 ii 条网线连接个主机 aiai 和 bibi。保证任意两台主机可以通过有限根网线直接或者间接地相连。受制于信息发送的功率,主机 aa 能够直接将信息传输给主机 bb 当且仅当两个主机在可以通过不超过 kk 根网线直接或者间接的相连。
在计算机网络中,数据的传输往往需要通过若干次转发。假定小 C 需要将数据从主机 aa 传输到主机 b(a≠b)b(a≠b),则其会选择出若干台用于传输的主机 c1c1 = aa, c2c2, · · · , cm−1cm−1, cmcm = bb,并按照如下规则转发:对于所有的 1≤i<m1≤i<m, 主机 cici 将信息直接发送给 ci+1ci+1。
每台主机处理信息都需要一定的时间,第 ii 台主机处理信息需要 vivi 单位的时间。数据在网络中的传输非常迅速,因此传输的时间可以忽略不计。据此,上述传输过程花费的时间为 ∑mi=1vci∑i=1mvci。
现在总共有 qq 次数据发送请求,第 ii 次请求会从主机 sisi 发送数据到主机 titi。小 C想要知道,对于每一次请求至少需要花费多少单位时间才能完成传输。
【输入】
输入的第一行包含三个正整数 nn, QQ, kk,分别表示网络主机个数,请求个数,传输参数。数据保证 1≤n≤2×1051≤n≤2×105, 1≤Q≤2×1051≤Q≤2×105, 1≤k≤31≤k≤3。
输入的第二行包含 nn 个正整数,第 ii 个正整数表示 vivi,保证 1≤vi≤1091≤vi≤109。
接下来 n−1n−1 行,第 ii 行包含两个正整数 aiai, bibi,表示一条连接主机 aiai, bibi 的网线。保证 1≤ai,bi≤n1≤ai,bi≤n。
接下来 QQ 行,第 ii 行包含两个正整数 sisi, titi,表示一次从主机 sisi 发送数据到主机 titi的请求。保证 1≤si1≤si, ti≤nti≤n, si≠tisi≠ti。
【输出】
QQ 行,每行一个正整数,表示第 ii 次请求在传输的时候至少需要花费多少单位的时间。
【输入样例】
7 3 3 1 2 3 4 5 6 7 1 2 1 3 2 4 2 5 3 6 3 7 4 7 5 6 1 2【输出样例】
12 12 3【提示】
【样例 1 解释】
对于第一组请求,由于主机 44, 77 之间需要至少 44 根网线才能连接,因此数据无法在两台主机之间直接传输,其至少需要一次转发;我们让其在主机 11 进行一次转发,不难发现主机 11 和主机 44, 77 之间都只需要两根网线即可连接,且主机 11 的数据处理时间仅为 11,为所有主机中最小,因此最少传输的时间为 4+1+7=124+1+7=12。
对于第三组请求,由于主机 11, 22 之间只需要 11 根网线就能连接,因此数据直接传输就是最优解,最少传输的时间为 1+2=31+2=3。
【数据范围】
对于所有的测试数据,满足 1≤n≤2×1051≤n≤2×105, 1≤Q≤2×1051≤Q≤2×105, 1≤k≤31≤k≤3, 1≤ai,bi≤n1≤ai,bi≤n, 1≤si,ti≤n1≤si,ti≤n, si≠tisi≠ti。
测试点 n Q k 特殊性质 1 ≤ 10 ≤ 10 =2 是 2 =3 3 ≤ 200 ≤ 200 =2 4,5 =3 6,7 ≤ 2000 ≤ 2000 =1 否 8,9 =2 10,11 =3 12,13 ≤ 2 × 105 ≤ 2 × 105 =1 14 ≤ 5 × 104 ≤ 5 × 104 =2 是 15,16 ≤105 ≤ 105 17,18,19 ≤2 × 105 ≤ 2 × 105 否 20 ≤5 × 104 ≤ 5 × 104 =3 是 21,22 ≤105 ≤ 105 23,24,25 ≤2 × 105 ≤ 2 × 105 否 特殊性质:保证 ai=i+1ai=i+1,而 bibi 则从 11, 22, . . . , ii 中等概率选取。
代码:
#include<bits/stdc++.h> using namespace std; namespace IO { bool EOFstate = 0; template<typename T>inline void read(T& x) { x = 0; int f = 1; char c = getchar(); while(('0' > c || c > '9') && !EOFstate) { if(c == '-')f = -1; c = getchar(), EOFstate = c == EOF; } while('0' <= c && c <= '9')x = (x << 3) + (x << 1) + c - '0', c = getchar(); x *= f; } template<typename T = int>inline T read() { T x; x = 0; int f = 1; char c = getchar(); while(('0' > c || c > '9') && !EOFstate) { if(c == '-')f = -1; c = getchar(), EOFstate = c == EOF; } while('0' <= c && c <= '9')x = (x << 3) + (x << 1) + c - '0', c = getchar(); x *= f; return x; } template<typename T>inline void write(T x, char end = ' ') { if(x == 0)return putchar('0'), putchar(end), void(); if(x < 0)putchar('-'), x = -x; char c[21], cnt = 0; while(x)c[cnt++] = x % 10 + '0', x /= 10; while(cnt)putchar(c[--cnt]); putchar(end); } }using namespace IO; const int N = 2e5 + 5, K = 20, A = 3; #define ll long long #define getB(x) (31-__builtin_clz(x)) int n, q, lim; struct Node { ll a[A][A]; inline void clear() { memset(a, 0x3f, sizeof(a)); a[0][0] = 0; } inline void ext()//贪心扩展状态 { for(int i = 0; i < lim - 1; ++i) for(int j = lim - 1; ~j; --j) a[i + 1][j] = min(a[i + 1][j], a[i][j]); for(int i = 0; i < lim; ++i) for(int j = lim - 1; j > 0; --j) a[i][j - 1] = min(a[i][j - 1], a[i][j]); } inline void init(ll v) { memset(a, 0x3f, sizeof(a)); a[0][lim - 1] = v; for(int i = 1; i < lim; ++i) a[i][i - 1] = 0; } }; Node up[N][K]; int fa[N][K], dep[N]; int val[N]; int head[N], to[N << 1], nxt[N << 1], tot; inline void _add(int f, int t) { to[++tot] = t, nxt[tot] = head[f], head[f] = tot; } inline void add(int a, int b) { _add(a, b), _add(b, a); } void dfs(int p, int f) { dep[p] = dep[f] + 1, fa[p][0] = f; for(int i = head[p]; i; i = nxt[i]) if(to[i] != f) dfs(to[i], p); } inline void extend(int p) { up[p][0].init(val[p]); if(lim == 3) for(int i = head[p]; i; i = nxt[i]) up[p][0].a[1][1] = min(up[p][0].a[1][1], val[to[i]]*1ll); up[p][0].ext(); } inline void merge(Node& T, Node f, Node g)//合并两根网线 { for(int a = 0; a < lim; ++a) for(int b = 0; b < lim; ++b) { ll v = 0x3f3f3f3f3f3f3f3f; for(int j = 0; j < lim; ++j) v = min(v, f.a[a][j] + g.a[j][b]); T.a[a][b] = v; } } inline void init() { int mx = getB(n); for(int k = 1, t; k <= mx; ++k) for(int i = 1; i <= n; ++i) { t = fa[i][k - 1]; fa[i][k] = fa[t][k - 1]; merge(up[i][k], up[i][k - 1], up[t][k - 1]); } } Node vala, valb; inline int LCA(int a, int b) { vala.clear(), valb.clear(); if(dep[a] < dep[b]) swap(a, b), swap(vala, valb); for(int i = dep[a] - dep[b], k = i & -i; i; i ^= k, k = i & -i)//没什么用的卡常(莫非是getB常数太大) merge(vala, vala, up[a][getB(k)]), a = fa[a][getB(k)]; if(a == b) return a; for(int i = getB(dep[a]); ~i; --i)//有点用的卡常 if(fa[a][i] != fa[b][i]) merge(vala, vala, up[a][i]), merge(valb, valb, up[b][i]), a = fa[a][i], b = fa[b][i]; merge(vala, vala, up[a][0]), merge(valb, valb, up[b][0]); return fa[a][0]; } signed main() { read(n), read(q), read(lim); for(int i = 1; i <= n; ++i) read(val[i]); for(int i = 2; i <= n; ++i) add(read(), read()); dfs(1, 0); for(int i = 1; i <= n; ++i) extend(i); init(); for(int i = 1, s, t; i <= q; ++i) { read(s), read(t); int lca = LCA(s, t); merge(vala, vala, up[lca][0]);//将lca也合入一根网线 ll v = LLONG_MAX; for(int i = 0; i < lim; ++i) v = min(v, vala.a[0][i] + valb.a[0][lim - i - 1]); write(v, '\n'); } return 0; }