• 洛谷 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

  • 相关阅读:
    学习Python比较好的书籍推荐
    将Python分成7个阶段学习,你会发现学习Python真的很简单
    web前端开发学习 自学web前端需要掌握哪些知识点?
    零基础想转行从事Python?需要掌握如下技能
    每日干货丨C++语言主流开发工具推荐!
    适合零基础人群学习的Python入门教程
    Python爬虫学习教程 猫眼电影网站视频爬取!【附源码】
    Python爬虫学习教程 bilibili网站视频爬取!【附源码】
    Python爬虫技术要学到什么程度才可以找到工作?
    零基础如何高效的学习好Python爬虫技术?
  • 原文地址:https://www.cnblogs.com/xixike/p/15395800.html
Copyright © 2020-2023  润新知