zoukankan      html  css  js  c++  java
  • Luogu 4768 [NOI2018]归程

    并不会写Kruskal重构树,两个$log$跑得比较卡。

    首先考虑一下没有强制在线的要求怎么办,有一个比较容易想到的做法就是先跑一遍最短路,然后把所有边按照海拔从大到小排序,把所有询问的海拔也从大到小排序,然后对于每一个询问$(x, h)$把所有海拔高于$h$的边都连上,然后看一看点$x$的能到达的点中离$1$距离最小的点是多少。

    这就是一个并查集可以维护的东西了。

    强制在线怎么办……直接大力把这个并查集可持久化……就没了。

    时间复杂度$O(nlog^2n)$。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef pair <int, int> pin;
    
    const int N = 2e5 + 5;
    const int M = 5e5 + 5;
    
    int testCase, n, m, qn, tot, head[N], dis[N];
    int numCnt, in[M], ed[M], pos[M];
    bool vis[N];
    
    struct Edge {
        int to, nxt, val;
    } e[M << 1];
    
    inline void add(int from, int to, int val) {
        e[++tot].to = to;
        e[tot].val = val;
        e[tot].nxt = head[from];
        head[from] = tot;
    }
    
    struct Pathway {
        int x, y, val, h, id;
    } path[M];
    
    bool cmp(const Pathway &u, const Pathway &v) {
        return u.h < v.h;
    }
    
    inline void read(int &X) {
        X = 0; char ch = 0; int op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    priority_queue <pin> Q;
    void dij() {
        memset(dis, 0x3f, sizeof(dis));
        memset(vis, 0, sizeof(vis));
        Q.push(pin(dis[1] = 0, 1));
        for(; !Q.empty(); ) {
            int x = Q.top().second; Q.pop();
            if(vis[x]) continue;
            vis[x] = 1;
            for(int i = head[x]; i; i = e[i].nxt) {
                int y = e[i].to;
                if(dis[y] > dis[x] + e[i].val) {
                    dis[y] = dis[x] + e[i].val;
                    Q.push(pin(-dis[y], y));
                }
            }
        }
    }
    
    inline int min(int x, int y) {
        return x > y ? y : x;
    }
    
    inline void swap(int &x, int &y) {
        int t = x; x = y; y = t;
    }
    
    namespace PUfs {
        struct Node {
            int lc, rc, ufs, dis, dep;
        } s[N * 60];
        int root[M], nodeCnt = 0LL;
        
        #define lc(p) s[p].lc
        #define rc(p) s[p].rc
        #define ufs(p) s[p].ufs
        #define dis(p) s[p].dis
        #define dep(p) s[p].dep
        #define mid ((l + r) >> 1)
        
        inline void clear(int p) {
            lc(p) = rc(p) = ufs(p) = dis(p) = dep(p) = 0;
        }
        
        void build(int &p, int l, int r, int type) {
            p = ++nodeCnt;
            if(l == r) {
                ufs(p) = l, dep(p) = 0; 
                if(!type) dis(p) = 0;
                else dis(p) = dis[l];
                return;
            }
            
            build(lc(p), l, mid, type);
            build(rc(p), mid + 1, r, type);
        }
        
        void modify(int &p, int l, int r, int x, int nowUfs, int nowDis, int pre) {
            p = ++nodeCnt;
            if(l == r) {
                ufs(p) = nowUfs, dis(p) = nowDis, dep(p) = dep(pre);
                return;
            }
            
            lc(p) = lc(pre), rc(p) = rc(pre);
            if(x <= mid) modify(lc(p), l, mid, x, nowUfs, nowDis, lc(pre));
            else modify(rc(p), mid + 1, r, x, nowUfs, nowDis, rc(pre));
        }
        
        void mDis(int &p, int l, int r, int x, int nowDis, int pre) {
            p = ++nodeCnt;
            if(l == r) {
                ufs(p) = ufs(pre), dep(p) = dep(pre), dis(p) = nowDis;
                return;
            }
            
            lc(p) = lc(pre), rc(p) = rc(pre);
            if(x <= mid) mDis(lc(p), l, mid, x, nowDis, lc(pre));
            else mDis(rc(p), mid + 1, r, x, nowDis, rc(pre));
        }
        
        void add(int p, int l, int r, int x) {
            if(l == r) {
                ++dep(p);
                return;
            }
            
            if(x <= mid) add(lc(p), l, mid, x);
            else add(rc(p), mid + 1, r, x);
        }
        
        int query(int p, int l, int r, int x) {
            if(l == x && x == r) return p;
            
            if(x <= mid) return query(lc(p), l, mid, x);
            else return query(rc(p), mid + 1, r, x);
        }
            
        int find(int now, int x) {
            int f = query(now, 1, n, x);
            if(s[f].ufs == x) return f;
            else return find(now, s[f].ufs);
        }
        
        inline void merge(int k, int x, int y) {
            root[k] = root[k + 1];
            int fx = find(root[k], x), fy = find(root[k], y);
            if(s[fx].ufs == s[fy].ufs) return;
            if(s[fx].dep > s[fy].dep) swap(fx, fy);
            int dis = min(s[fx].dis, s[fy].dis);
            modify(root[k], 1, n, s[fx].ufs, s[fy].ufs, dis, root[k + 1]);
            if(dis != s[fy].dis) mDis(root[k], 1, n, s[fy].ufs, dis, root[k]);
            if(s[fx].dep == s[fy].dep) add(root[k], 1, n, s[fy].ufs);
        }
        
        #undef mid
        
    } using namespace PUfs;
    
    inline void prework() {
        for(int i = 1; i <= nodeCnt; i++) clear(i);
        nodeCnt = 0; memset(root, 0, sizeof(root));
        build(root[m + 1], 1, n, 1);
        build(root[0], 1, n, 0);
    }
    
    inline int bfind(int val) {
        int ln = 0, rn = numCnt, mid, res;
        for(; ln <= rn; ) {
            mid = (ln + rn) / 2;
            if(in[mid] <= val) ln = mid + 1, res = mid;
            else rn = mid - 1;
        }
        return res;
    }
    
    int main() {
    //    freopen("return.in", "r", stdin);
    //    freopen("return.out", "w", stdout);
        
        for(read(testCase); testCase--; ) {
            tot = numCnt = 0; memset(head, 0, sizeof(head));
            
            read(n), read(m);
            for(int i = 1; i <= m; i++) {
                read(path[i].x), read(path[i].y), read(path[i].val), read(path[i].h);
                in[++numCnt] = path[i].h;
                path[i].id = i;
                add(path[i].x, path[i].y, path[i].val), add(path[i].y, path[i].x, path[i].val);
            }
            
            sort(in + 1, in + 1 + numCnt);
            numCnt = unique(in + 1, in + 1 + numCnt) - in - 1;
            
    /*        for(int i = 1; i <= numCnt; i++)
                printf("%d ", in[i]);
            printf("
    ");   */
            
            for(int i = 1; i <= m; i++) 
                path[i].h = lower_bound(in + 1, in + 1 + numCnt, path[i].h) - in;
            
            dij();
            
    /*        for(int i = 1; i <= n; i++)
                printf("%d ", dis[i]);
            printf("
    ");   */
            
            prework();
            sort(path + 1, path + 1 + m, cmp);
            
    /*        printf("
    ");
            for(int i = 1; i <= m; i++)
                printf("%d %d %d %d
    ", path[i].x, path[i].y, path[i].val, path[i].h);   */
            
            for(int i = m; i >= 1; i--) {
                merge(i, path[i].x, path[i].y);
                if(path[i].h != path[i - 1].h) ed[path[i].h] = i;    
            }    
            
    /*        for(int i = 1; i <= numCnt; i++)
                printf("%d ", ed[i]);
            printf("
    ");   */
            
            for(int i = 1; i < numCnt; i++) pos[i] = ed[i + 1];
            pos[numCnt] = m + 1;
            
    /*        for(int i = 1; i <= numCnt; i++)
                printf("%d ", pos[i]);
            printf("
    ");   */
            
    /*        for(int j = 1; j <= n; j++)
                    printf("%d ", s[query(root[m + 1], 1, n, j)].dis);
                printf("
    ");   */
            
    /*        for(int i = 1; i <= numCnt; i++) {
                printf("%d: ", i);
                for(int j = 1; j <= n; j++)
                    printf("%d ", s[query(root[pos[i]], 1, n, j)].ufs);
                printf("
    ");
            }
            
            for(int i = 1; i <= numCnt; i++) {
                printf("%d: ", i);
                for(int j = 1; j <= n; j++)
                    printf("%d ", s[query(root[pos[i]], 1, n, j)].dis);
                printf("
    ");
            }    */
            
    /*        for(int i = 1; i <= numCnt; i++)
                printf("%d ", pos[i]);
            printf("
    ");    */
            
    //        in[++numCnt] = path[m].h + 1;
            
            int K, S, ans = 0;
            read(qn), read(K), read(S);
            for(int x, h; qn--; ) {
                read(x), read(h);
                x = (x + K * ans - 1) % n + 1, h = (h + K * ans) % (S + 1);
                int rt = bfind(h);
                rt = pos[rt];
                rt = find(root[rt], x);
                printf("%d
    ", ans = s[rt].dis);
            }
        }
        return 0;
    }
    View Code

    缅怀$spfa$。

  • 相关阅读:
    主键索引就是聚集索引吗?
    聚集索引以及非聚集索引
    IO阻塞模型、IO非阻塞模型、多路复用IO模型
    Log4j的使用说明
    前置机是什么
    转:图文理解区块链
    DQL、DML、DDL、DCL全名是啥?
    OLAP和OLTP的区别
    JAVA之运算符优先级
    JAVA之异常处理(一)
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9668715.html
Copyright © 2011-2022 走看看