zoukankan      html  css  js  c++  java
  • 洛谷 P4768 [NOI2018] 归程

    Description

    洛谷传送门

    Solution

    (Kruskal) 重构树好题。

    我们先按照水位 (a),建 (Kruskal) 重构树。具体来讲:按水位从高到低排序,每次选出剩余边中水位最高的一条边插入到树中,这样就建成了一个小根堆。

    然后我们再来考虑询问。

    对于一个水位线 (p),若 (p < Kruskal) 重构树上的点 (x) 的水位,那么在以 (x) 为根的子树中,开车是可以随意通行的,对答案没有贡献。

    (p > t[x].dep)(p < t[fa[x]].dep),那么它就不得不在点 (fa[x]) 下车,所以对答案的贡献就是从 (fa[x]) 到 1 的距离。

    那这个距离该如何算呢?

    这个很简单,只需要提前跑个 (dijkstra) 堆优化预处理一下即可,千万千万千万不要使用 (spfa) (逃。

    我们对于一组询问 (v p),找到上述的 (x) 节点即可。

    现在的问题就是如何找到这样的节点,我们考虑倍增,倍增向上跳(就是个板子),具体见代码。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    inline int read(){
        int x = 0;
        char ch = getchar();
        while(ch < '0' || ch > '9') ch = getchar();
        while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x;
    }
    
    const int N = 4e5 + 10;
    int T, n, m, last;
    struct node{
        int u, v, l, a, nxt;
        bool operator < (const node &b) const{
            return a > b.a;
        }
    }e[N << 1], tmp[N << 1], edge[N << 1];
    int head[N], tot, dis[N];
    struct heap{
        int x, dis;
        bool operator < (const heap &b) const{
            return dis > b.dis;
        }
    };
    int f[N], cnt;
    
    inline void Add(int x, int y, int z){
        edge[++tot].v = y, edge[tot].l = z, edge[tot].nxt = head[x];
        head[x] = tot;
    }
    
    inline void dijkstra(){
        priority_queue <heap> q;
        memset(dis, 0x3f, sizeof(dis));
        dis[1] = 0;
        q.push((heap){1, 0});
        while(!q.empty()){
            heap now = q.top();
            q.pop();
            int x = now.x;
            if(dis[x] < now.dis) continue;
            for(int i = head[x]; i; i = edge[i].nxt){
                int y = edge[i].v;
                if(dis[y] > dis[x] + edge[i].l){
                    dis[y] = dis[x] + edge[i].l;
                    q.push((heap){y, dis[y]});
                }
            }
        }
    }
    
    inline int find(int x){
        return f[x] == x ? x : f[x] = find(f[x]);
    }
    
    inline void add(int x, int y){
        edge[++tot].v = y, edge[tot].nxt = head[x];
        head[x] = tot;
    }
    
    inline void kruskal(){
        sort(e + 1, e + 1 + m);
        for(int i = 1; i <= n; i++)
            f[i] = i;
        cnt = n;
        int num = 0;
        for(int i = 1; i <= m; i++){
            int fu = find(e[i].u), fv = find(e[i].v);
            if(fu != fv){
                num++;
                tmp[++cnt].a = e[i].a;
                f[fu] = f[fv] = f[cnt] = cnt;
                add(cnt, fu), add(cnt, fv);
            }
            if(num == n - 1) break;
        }
    }
    
    int fa[N][20], dep[N];
    
    inline void dfs(int x, int p){
        dep[x] = dep[p] + 1, fa[x][0] = p;
        for(int i = 1; i <= 19; i++)
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = edge[i].nxt){
            int y = edge[i].v;
            dfs(y, x);
            tmp[x].l = min(tmp[x].l, tmp[y].l);
        }
    }
    
    inline int query(int x, int y){
        for(int i = 19; i >= 0; i--)
            if(dep[x] - (1 << i) > 0 && tmp[fa[x][i]].a > y)
                x = fa[x][i];
        return tmp[x].l;
    }
    
    inline void solve(){
        kruskal();
        dfs(cnt, 0);
        int q = read(), k = read(), s = read();
        while(q--){
            int x = (k * last + read() - 1) % n + 1, y = (k * last + read()) % (s + 1);
            printf("%d
    ", last = query(x, y));
        }
    }
    
    inline void init(){
        memset(head, 0, sizeof(head));
        memset(fa, 0, sizeof(fa));
        memset(f, 0, sizeof(f));
        memset(tmp, 0, sizeof(tmp));
        memset(edge, 0, sizeof(edge));
        last = tot = 0;
    }
    
    int main(){
        T = read();
        while(T--){
            init();
            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();
                Add(e[i].u, e[i].v, e[i].l), Add(e[i].v, e[i].u, e[i].l);
            }
            dijkstra();
            for(int i = 1; i <= n; i++) tmp[i].l = dis[i];
            for(int i = n + 1; i <= (n << 1); i++) tmp[i].l = INF;
            memset(head, 0, sizeof(head)), tot = 0;
            solve();
        }
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15395800.html

  • 相关阅读:
    PHP基础学习笔记(一)
    安装wampserver之后,浏览器中输入localhost页面显示IIS7解决办法
    HTML5常识总结(一)
    AngularJs中的服务
    AngularJs中的directives(指令part1)
    Happy Number——LeetCode
    Binary Tree Zigzag Level Order Traversal——LeetCode
    Construct Binary Tree from Preorder and Inorder Traversal——LeetCode
    Construct Binary Tree from Inorder and Postorder Traversal——LeetCode
    Convert Sorted Array to Binary Search Tree——LeetCode
  • 原文地址:https://www.cnblogs.com/xixike/p/15395800.html
Copyright © 2011-2022 走看看