【SDOI2017】天才黑客

北城余情 提交于 2019-12-01 13:20:28

题面

题解

这是好久之前菊开讲的一道题目了。

可以发现在这道题目中,边比点更加重要,所以我们化边为点,将边权改为点权,边与边之间的边权就是题目所给的Trie树上LCA深度的和。

想到一个平方的暴力,每条边和它连向的点的出边连一条边。下一步考虑怎么优化。

对于每一个点,将它的入边和出边都拿出来,按照dfs序排序,那么可以考虑将每个点拆成入点和出点,因为\(\operatorname{lcp}(i, j)\)的值是\(i \to j\)之间所有的边的\(\operatorname{lcp}\)的最小值,于是前后缀优化连边就可以了。

可以考虑使用下面这个图来帮助理解:

说起来容易做起来难,代码留给读者作为练习

代码

#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)  inline int read() {     int data = 0, w = 1; char ch = getchar();     while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();     if (ch == '-') w = -1, ch = getchar();     while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();     return data * w; }  const int N(50010); struct edge { int to, dis; }; int T, n, m, K, val[N * 20], pos[N], dis[N * 20], vis[N * 20], cur; std::vector<int> in[N], out[N]; std::vector<edge> G[N * 20]; namespace Tree {     int fa[N], size[N], heavy[N], dfn[N], bel[N], dep[N], cnt; std::vector<int> T[N];     inline void Add(int x, int y) { T[x].push_back(y); }     void dfs(int x)     {         size[x] = 1, heavy[x] = 0;         for (auto i : T[x])         {             fa[i] = x, dep[i] = dep[x] + 1, dfs(i), size[x] += size[i];             if (size[heavy[x]] < size[i]) heavy[x] = i;         }     }      void dfs(int x, int chain)     {         dfn[x] = ++cnt, bel[x] = chain;         if (heavy[x]) dfs(heavy[x], chain);         for (auto i : T[x]) if (i != heavy[x]) dfs(i, i);     }      int LCA(int x, int y)     {         for (; bel[x] != bel[y]; x = fa[bel[x]])             if (dfn[bel[x]] < dfn[bel[y]]) std::swap(x, y);         return dfn[x] < dfn[y] ? dep[x] : dep[y];     } }  void Dijkstra() {     std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >,         std::greater<std::pair<int, int> > > Q;     memset(dis, 127, (cur + 1) << 2), memset(vis, 0, sizeof vis);     for (auto i : out[1]) Q.push(std::make_pair(dis[i] = val[i], i));     while (!Q.empty())     {         int x = Q.top().second; Q.pop(); if (vis[x]) continue; vis[x] = 1;         for (auto i : G[x]) if (dis[x] + val[i.to] + i.dis < dis[i.to])             Q.push(std::make_pair(dis[i.to] = dis[x] + val[i.to] + i.dis, i.to));     } }  int Abs(int x) { return x < 0 ? -x : x; } int cmp(int x, int y) { return Tree::dfn[pos[Abs(x)]] < Tree::dfn[pos[Abs(y)]]; } void Link(int x) {     static int stk[N], p1[N], p2[N], q1[N], q2[N]; int top = 0;     for (auto i : in[x]) stk[++top] = i;     for (auto i : out[x]) stk[++top] = -i;     std::sort(stk + 1, stk + top + 1, cmp);     for (int i = 1; i <= top; i++)         p1[i] = ++cur, p2[i] = ++cur, q1[i] = ++cur, q2[i] = ++cur;     for (int i = 2; i <= top; i++)         G[p1[i - 1]].push_back((edge) {p1[i], 0}),         G[q1[i - 1]].push_back((edge) {q1[i], 0}),         G[p2[i]].push_back((edge) {p2[i - 1], 0}),         G[q2[i]].push_back((edge) {q2[i - 1], 0});     for (int i = 1; i <= top; i++)         if (stk[i] > 0) G[stk[i]].push_back((edge) {p1[i], 0}),                         G[stk[i]].push_back((edge) {p2[i], 0});         else stk[i] = -stk[i], G[q1[i]].push_back((edge) {stk[i], 0}),                                G[q2[i]].push_back((edge) {stk[i], 0});     for (int i = 1, x; i < top; i++)         x = Tree::LCA(pos[stk[i]], pos[stk[i + 1]]),         G[p1[i]].push_back((edge) {q1[i + 1], x}),         G[p2[i + 1]].push_back((edge) {q2[i], x}); }  int main() { #ifndef ONLINE_JUDGE     file(cpp); #endif     for (T = read(); T--; )     {         n = read(), m = cur = read(), K = read();         memset(val, 0, sizeof val), Tree::cnt = 0;         for (int i = 1, x, y; i <= m; i++)             x = read(), y = read(), val[i] = read(), pos[i] = read(),             out[x].push_back(i), in[y].push_back(i);         for (int i = 1, x, y; i < K; i++)             x = read(), y = read(), read(), Tree::Add(x, y);         Tree::dfs(1), Tree::dfs(1, 1);         for (int i = 2; i <= n; i++) Link(i);         Dijkstra();         for (int i = 2; i <= n; i++)         {             int ans = 2e9;             for (auto x : in[i]) ans = std::min(ans, dis[x]);             printf("%d\n", ans);         }         for (int i = 1; i <= cur; i++) G[i].clear();         for (int i = 1; i <= n; i++) in[i].clear(), out[i].clear();         for (int i = 1; i <= K; i++) Tree::T[i].clear();     }     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!