Luogu P4768 [NOI2018]归程

题目链接 (Click) (Here)

(Kruskal)重构树的好题。想到的话就很好写,想不到乱搞的难度反而相当高。

按照点的水位,建出来满足小根队性质的(Kruskal)重构树,这样一个点的子树里的点就是所有可以开车到达的点。做一遍最短路预处理,然后树上求一个子树(min),就可以得到子树里面的点到点(1)的最短距离。注意需要初始化。

#include <bits/stdc++.h>
using namespace std;

const int N = 800010;
const int INF = 0x7fffffff;

struct _edge {int u, v, l, a;}_e[N];

bool cmp (_edge lhs, _edge rhs) {
    return lhs.a > rhs.a;
}

struct Graph {
    int cnt, head[N];

    struct edge {
        int nxt, to, w;
    }e[N << 1];
    
    void Init () {
        cnt = 0;
        memset (head, 0, sizeof (head));
    }

    void add_edge (int u, int v, int w) {
        e[++cnt] = (edge) {head[u], v, w}; head[u] = cnt;
    }
}G, krus;

int read () {
    int s = 0, w = 1, ch = getchar ();
    while ('9' < ch || ch < '0') {
        if (ch == '-') w = -1;
        ch = getchar ();
    }
    while ('0' <= ch && ch <= '9') {
        s = s * 10 + ch - '0';
        ch = getchar ();
    }
    return s * w;
}

int T, n, m, Q, K, S, tot, fa[N], _high[N];

int find (int x) {
    return fa[x] == x ? x : fa[x] = find (fa[x]);
}

int deep[N], fafa[N][20];

int dis[N], mindis[N];

void dfs (int u, int fa) {
    fafa[u][0] = fa;
    mindis[u] = krus.head[u] == 0 ? dis[u] : INF;
    deep[u] = deep[fa] + 1;
    for (int i = 1; (1 << i) <= deep[u]; ++i) {
        fafa[u][i] = fafa[fafa[u][i - 1]][i - 1];
    }
    for (int i = krus.head[u]; i; i = krus.e[i].nxt) {
        int v = krus.e[i].to;
        dfs (v, u);
        mindis[u] = min (mindis[u], mindis[v]);
    }
}

void kruskal () {
    sort (_e + 1, _e + 1 + m, cmp);
    tot = n;
    for (int i = 1; i <= n; ++i) fa[i] = i;
    for (int i = 1; i <= m; ++i) {
        int u = find (_e[i].u);
        int v = find (_e[i].v);
        if (u != v) {
            int T = ++tot;
            _high[T] = _e[i].a;
            krus.add_edge (T, u, 0);
            krus.add_edge (T, v, 0);
            fa[T] = fa[u] = fa[v] = T;
        }
    }
    dfs (tot, 0);
}

struct Node {
    int pos, dis;

    bool operator < (Node rhs) const {
        return dis > rhs.dis;
    }
};

priority_queue <Node> q;

void dijkstra () {
    for (int i = 1; i <= n; ++i) dis[i] = i == 1 ? 0 : INF;
    q.push ((Node) {1, 0});
    while (!q.empty ()) {
        Node u = q.top (); q.pop ();
        if (dis[u.pos] < u.dis) continue;
        for (int i = G.head[u.pos]; i; i = G.e[i].nxt) {
            int v = G.e[i].to;
            if (dis[v] > dis[u.pos] + G.e[i].w) {
                dis[v] = dis[u.pos] + G.e[i].w;
                q.push ((Node) {v, dis[v]});
            }
        }
    }
} 

int query (int u, int p) {
    //u 出发节点 p 水位线
    for (int i = 19; i >= 0; --i) {
        if (_high[fafa[u][i]] > p) {
            u = fafa[u][i];
        }
    }
    // printf ("u = %d
", u);
    return mindis[u];
}

void Init () {
    G.Init ();
    krus.Init ();
    memset (fafa, 0, sizeof (fafa));
    memset (_high, 0, sizeof (_high));
    memset (mindis, 0, sizeof (mindis));
}

int main () {
	//freopen ("data.in", "r", stdin);
    T = read ();
    while (T--) {
        Init ();
		printf ("T = %d
", T);
        n = read (), m = read ();
        for (int i = 1; i <= m; ++i) {
            _e[i].u = read ();
            _e[i].v = read ();
            _e[i].l = read ();
            _e[i].a = read ();
            G.add_edge (_e[i].u, _e[i].v, _e[i].l);
            G.add_edge (_e[i].v, _e[i].u, _e[i].l); //建双向边
        }
        int lastans = 0;
        dijkstra ();
        kruskal ();
        Q = read (), K = read (), S = read ();
        for (int i = 1; i <= Q; ++i) {
            static int v, p, v0, p0;
            v0 = read (), p0 = read ();
            v = (v0 + K * lastans - 1) % n + 1;
            p = (p0 + K * lastans) % (S + 1);
            printf ("%d
", lastans = query (v, p));
        }
    }
} 

原文地址:https://www.cnblogs.com/maomao9173/p/10553562.html