圆方树小结

圆方树

jzoj 1914. 【2011集训队出题】最短路
这是道圆方树+倍增LCA裸题。
圆方树,顾名思义,就是圆点和方点所组成的树。
而方点就是一个圆的根,一般都是\(dfs\)时第一个到这个圆的那个位置,然后另附一个点当做方点。然后圆所组成的点都连向方点。
而对于这种圆方边的边权,则为它到根的最近值。
从而将一个仙人掌转成了一棵树。

然后对于这棵树,我们就可以用倍增来求出两两点之间的最短路了。
注意的是,对于最后走到的位置,我们要看看它是从上面绕近还是直接从下面走更优!!!
就这样子了。

\(code\)

#include <cstdio>
#include <algorithm>
#define N 100010
#define mem(x, a) memset(x, a, sizeof x)
#define fo(x, a, b) for (int x = (a); x <= (b); x++)
#define fd(x, a, b) for (int x = (a); x >= (b); x--)
using namespace std;
struct node{int v, fr, w;}e[N << 1];
struct edge{int v, fr;}g[N << 1];
int n, n1, m, Q, tail[N], cnt = 1, len[N];
int dfn[N], low[N], fa[N], tot = 0, ri[N];
int f[N][16], l[N][16], cir[N], fz[N], dep[N];
int head[N], cnt1 = 1;
int z[N], top = 0;

inline int read()
{
    int x = 0, f = 0; char c = getchar();
    while (c < '0' || c > '9') f = (c == '-') ? 1 : f, c = getchar();
    while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return f ? -x : x;
}

inline void add(int u, int v, int w) {e[++cnt] = (node){v, tail[u], w}; tail[u] = cnt;}

inline void add1(int u, int v) {g[++cnt1] = (edge){v, head[u]}; head[u] = cnt1;}

void tarjan(int x)
{
    dfn[x] = low[x] = ++tot, z[++top] = x;
    for (int p = tail[x], v; p; p = e[p].fr)
    {
        v = e[p].v;
        if (! dfn[v])
        {
            fa[v] = x, len[v] = e[p].w;
            tarjan(v);
            low[x] = min(low[x], low[v]);
            if (low[v] >= dfn[x])
            {
                cir[++n] = fz[z[top]], add1(x, n);
                int u = top;
                while (z[u] != x)   
                    cir[n] += len[z[u]], add1(n, z[u]), u--;
                ri[z[u]] = 0, u++;
                while (u <= top) ri[z[u]] = ri[z[u - 1]] + len[z[u]], u++;
                while (z[top] != x) l[z[top]][0] = min(ri[z[top]], cir[n] - ri[z[top]]), top--;
            }
        }
        else if (dfn[v] < low[x])
            fz[x] = e[p].w, low[x] = dfn[v];
    }
}

void get_dep(int x)
{
    for (int p = head[x], v; p; p = g[p].fr)
        v = g[p].v, f[v][0] = x, dep[v] = dep[x] + 1, get_dep(v);
}

int LCA(int x, int y)
{
    int ans = 0;
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 0, cha = dep[x] - dep[y]; cha; i++, cha >>= 1)
        if (cha & 1) ans += l[x][i], x = f[x][i];
    if (x == y) return ans;
    fd(i, 14, 0)
        if (f[x][i] != f[y][i])
        {
            ans += l[x][i] + l[y][i];
            x = f[x][i], y = f[y][i];
        }
    if (cir[f[x][0]]) return ans + min(abs(ri[x] - ri[y]), cir[f[x][0]] - abs(ri[x] - ri[y]));
    else return ans + l[x][0] + l[y][0];
}

int main()
{
    n = n1 = read(), m = read(), Q = read();
    fo(i, 1, m)
    {
        int u = read(), v = read(), w = read();
        add(u, v, w), add(v, u, w);
    }
    tarjan(1), get_dep(1);
    fo(j, 1, 14)
        fo(i, 1, n)
        {
            f[i][j] = f[f[i][j - 1]][j - 1];
            l[i][j] = l[i][j - 1] + l[f[i][j - 1]][j - 1];
        }
    fo(i, 1, Q)
    {
        int u = read(), v = read();
        printf("%d\n", LCA(u, v));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/jz929/p/12168579.html
今日推荐