• P4768 [NOI2018] 归程 做题记录


    听说这是个 Kruskal 重构树的练习题,于是往这方面想。

    先预处理出最短路 (dis)

    然后建出 Kruskal 重构树(枚举的边按照 (h) 从大到小排序)。

    然后对于一个询问 (v,p)

    (v) 不断向上跳,直到海拔 (<p) 为止,然后这个点的子树内的点都可到达。

    于是我们可以找到这个子树内 (dis) 最小的点就是答案。

    于是这题就做完了。

    最短路用 ( ext{Dij}) 或者 ( ext{SPFA})

    Kruskal 重构树用并查集

    (v) 向上跳用倍增。

    子树内 (dis) 最小的点可以 ST 表或者线段树。

    差不多 10:00 开始写的。

    现在是 11:39,我还没调出来,我看看我什么时候调出来。

    现在是 14:45,中间睡了两个小时的午觉,我调完了。

    /*
    Work by: Suzt_ilymics
    Problem: 不知名屑题
    Knowledge: 垃圾算法
    Time: O(能过)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define int long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 4e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    struct node {
        int fr, to, w, h;
        bool operator < (const node &b) const { return h > b.h; }
    }E[MAXN];
    
    struct Node {
        int id, val;
        bool operator < (const Node &b) const { return val > b.val;}
    };
    
    struct edge {
        int to, w, nxt;
    }e[MAXN << 1];
    int head[MAXN], num_edge = 1;
    
    int n, m, Q, K, S, Cnt;
    int val[MAXN], fa[MAXN], Log2[MAXN];
    int dis[MAXN], Dis[MAXN][21];
    int siz[MAXN], dfn[MAXN], fath[MAXN][22], H[MAXN][21];
    bool vis[MAXN];
    
    int read(){
        int s = 0, f = 0;
        char ch = getchar();
        while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
        return f ? -s : s;
    }
    
    namespace Cut {
        struct edge { int to, nxt; }e[MAXN << 1];
        int head[MAXN], num_edge = 1;
        int cnt = 0;
        void add_edge(int from, int to) { e[++num_edge] = (edge){to, head[from]}, head[from] = num_edge; }
        void dfs(int u, int fa) {
    //        cout<<u<<"
    ";
            siz[u] = 1, fath[u][0] = fa, dfn[u] = ++cnt;
            H[u][0] = fa <= n ? INF : val[fa]; Dis[cnt][0] = dis[u];
            for(int i = 1; i <= 20; ++i) {
                fath[u][i] = fath[fath[u][i - 1]][i - 1];
                H[u][i] = min(H[u][i - 1], H[fath[u][i - 1]][i - 1]);
            }
            for(int i = head[u]; i; i = e[i].nxt) {
                int v = e[i].to;
                if(v == fa) continue;
                dfs(v, u);
                siz[u] += siz[v];
            }
        }
    }
    
    void add_edge(int from, int to, int w) { e[++num_edge] = (edge){to, w, head[from]}, head[from] = num_edge; }
    void Dij() {
        priority_queue<Node> q;
        memset(dis, 0x3f, sizeof dis);
        memset(vis, false, sizeof vis);
        q.push((Node){1, 0}), dis[1] = 0;
        while(!q.empty()) {
            int u = q.top().id; q.pop();
            if(vis[u]) continue;
            vis[u] = true;
            for(int i = head[u]; i; i = e[i].nxt) {
                int v = e[i].to;
                if(dis[v] > dis[u] + e[i].w) {
                    dis[v] = dis[u] + e[i].w;
                    if(!vis[v]) q.push((Node){v, dis[v]});
                }
            }
        }
    }
    
    int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    void ExKruskal() {
        sort(E + 1, E + m + 1);
        for(int i = 1; i <= 2 * n; ++i) fa[i] = i;
        for(int i = 1; i <= m; ++i) {
            int u = E[i].fr, v = E[i].to, w = E[i].h;
            int uf = find(u), vf = find(v);
            if(uf != vf) {
                fa[uf] = fa[vf] = ++Cnt;
    //            cout<<"edge: "<<Cnt<<" "<<uf<<" 
    ";
    //            cout<<"edge: "<<Cnt<<" "<<vf<<" 
    ";
                Cut::add_edge(Cnt, uf), Cut::add_edge(Cnt, vf);
                val[Cnt] = w;
                if(Cnt == 2 * n - 1) break;
            }
        }
    }
    
    void Init() {
        for(int i = 1; i <= 20; ++i) {
            for(int j = 1; j + (1 << i) - 1 <= Cut::cnt; ++j) {
                Dis[j][i] = min(Dis[j][i - 1], Dis[j + (1 << i - 1)][i - 1]);
            }
        }
    }
    
    void Clear() {
        memset(head, false, sizeof head);
        memset(Cut::head, false, sizeof Cut::head);
        num_edge = Cut::num_edge = 1;
        memset(Dis, 0x3f, sizeof Dis);
        memset(val, false, sizeof val);
        memset(fath, false, sizeof fath);
        memset(H, false, sizeof H);
        Cut::cnt = 0;
    }
    
    signed main()
    {
        int T = read();
        for(int i = 2; i <= 400000; ++i) Log2[i] = Log2[i >> 1] + 1;
        while(T--) {
            Clear();
            n = read(), m = read();
            Cnt = n;
            for(int i = 1; i <= m; ++i) {
                E[i].fr = read(), E[i].to = read(), E[i].w = read(), E[i].h = read();
                add_edge(E[i].fr, E[i].to, E[i].w), add_edge(E[i].to, E[i].fr, E[i].w);
            }
            Dij();
            ExKruskal();
            Cut::dfs(Cnt, 0);
            Init();
    //        cout<<"dis: ";
    //        for(int i = 1; i <= n; ++i) cout<<dis[i]<<" "; puts("");
    //        for(int i = 1; i <= Cut::cnt; ++i) cout<<dfn[i]<<" "; puts("");
    //        for(int i = 1; i <= Cut::cnt; ++i) cout<<Dis[i][0]<<" "; puts("");
            Q = read(), K = read(), S = read();
            for(int i = 1, v, p, lst = 0; i <= Q; ++i) {
                v = read(), p = read();
                v = (v + K * lst - 1) % n + 1, p = (p + K * lst) % (S + 1);
    //            cout<<"v p: "<<v<<" "<<p<<" "<<"
    ";
                int x = v;
                for(int i = 20; i >= 0; --i) {
    //                cout<<"jump: "<<x<<" "<<i<<" "<<fath[x][i]<<" "<<H[x][i]<<" 
    ";
                    if(fath[x][i] && H[x][i] > p) {
    //                    cout<<i<<" 
    ";
                        x = fath[x][i];
                    }
                }
                int len = siz[x], l = dfn[x], r = dfn[x] + siz[x] - 1;
    //            cout<<x<<" "<<fath[x][0]<<" "<<H[x][0]<<" "<<l<<" "<<r<<" "<<"
    ";
                lst = min(Dis[l][Log2[len]], Dis[r - (1 << Log2[len]) + 1][Log2[len]]);
                printf("%lld
    ", lst);
            }
        }
        return 0;
    }
    

    好久没调过这么长的代码了,记得上次调的时候还是在上次。

    这道题好像就是 SPFA 之墓,所以我用的 Dij。/cy

    ST 表虽然没怎么用过,但显然比线段树好写。

    码力变强之后调题更快了,对于一些板子更自信了,所以我错哪了呢?

    • 定义了 lst 没有用;
    • 解密的公式写错了;
    • 题意理解错了,海拔严格高于才能走,代码一开始写的是不低于。
  • 相关阅读:
    js-20170816-Date对象
    js-20170804-Math对象
    js-20170619-string对象
    微信web开发者工具
    前端开发指南
    接口调试工具DHC
    CSS预处理器
    Weex
    Vue.js
    hbuilder
  • 原文地址:https://www.cnblogs.com/Silymtics/p/note-P4768.html
Copyright © 2020-2023  润新知