• 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));
            }
        }
    } 
    
    
  • 相关阅读:
    「题解」:07.16NOIP模拟T1:礼物
    「题解」:07.16NOIP模拟T2:通讯
    「题解」:图论专题总结
    07.07NOIP模拟赛
    [复习]平衡树splay
    「题解」:[组合数学][DP]:地精部落
    「题解」:[组合数学]:Perm 排列计数
    「题解」:[组合数学]:排队
    dp 杂题
    插头 dp 总结
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10553562.html
Copyright © 2020-2023  润新知