zoukankan      html  css  js  c++  java
  • CF464E The Classic Problem 题解

    Description

    洛谷传送门

    Solution

    emm……这是我为数不多的黑题之一,所以来写篇博客记录一下。

    我们发现边权过大,只能用高精度来算,但是这样的复杂度太劣了,无法通过此题。

    观察到边权只能是 (2^x),所以我们可以给它压成二进制数,然后跑最短路时单点加。

    我们再来考虑一下 (dijkstra) 需要哪些操作:

    • 区间加

    • 比大小

    先来看区间加,如果第 (x) 位为 0,那么赋值为 1 即可,如果第 (x) 位为一,那么我们需要向上找第一个为 0 的位,然后这一段区间赋值为 0,第一个为 0 的位赋值为 1。

    这个查找操作可以使用线段树上二分来实现,据说暴力查找也是可以过的,数据比较水。

    那区间赋值为 0 如何实现呢?主席树似乎不太能支持修改。我们可以建一棵全 0 主席树,然后修改时直接把这棵全 0 的树拍上去。

    再来看区间比大小,直接比较区间和即可。

    然后就是代码实现了,个人认为非常有助于提升码力,也让我对主席树的理解更深了一步。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <cmath>
    #define ull unsigned long long
    #define ll long long
    #define ls(x) t[x].l
    #define rs(x) t[x].r
    
    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 ll mod = 1e9 + 7;
    const int N = 2e5 + 10;
    int n, m, S, T;
    struct node{
        int v, w, nxt;
    }edge[N << 1];
    int head[N], tot;
    int inf;
    ll fac[N];
    struct Tree{
        ll sum;//sum:区间和
        int l, r, num;//num:区间 1 的个数
        friend bool operator == (Tree a,  Tree b){
            return a.sum == b.sum && a.num == b.num;
        }
    }t[N * 40];
    int root[N], cnt;//跟,节点编号
    int ans[N], path, pre[N];//记录路径
    bool vis[N];
    
    inline void add(int x, int y, int z){
        edge[++tot] = (node){y, z, head[x]};
        head[x] = tot;
    }
    
    inline void pushup(int rt){
        t[rt].num = t[ls(rt)].num + t[rs(rt)].num;
        t[rt].sum = (t[ls(rt)].sum + t[rs(rt)].sum) % mod;
    }
    
    inline void build(int &rt, int l, int r, int val){//建树
        if(!rt) rt = ++cnt;//一定要判断,不然会 RE
        if(l == r){
            t[rt].sum = fac[l] * val, t[rt].num = val;
            return;
        }
        int mid = (l + r) >> 1;
        build(ls(rt), l, mid, val);
        build(rs(rt), mid + 1, r, val);
        pushup(rt);
    }
    
    inline int query(int rt, int L, int R, int l, int r){//查询区间 1 的个数
        if(L <= l && r <= R) return t[rt].num;
        int mid = (l + r) >> 1;
        int res = 0;
        if(L <= mid) res += query(ls(rt), L, R, l, mid);
        if(R > mid) res += query(rs(rt), L, R, mid + 1, r);
        return res;
    }
    
    inline void update(int &rt, int l, int r, int val){//加点, 0 改为 1
        t[++cnt] = t[rt];
        rt = cnt;
        if(l == r){
            t[rt].sum = fac[l], t[rt].num = 1;
            return;
        }
        int mid = (l + r) >> 1;
        if(val <= mid) update(ls(rt), l, mid, val);
        else update(rs(rt), mid + 1, r, val);
        pushup(rt);
    }
    
    inline void clear(int &x, int y, int L, int R, int l, int r){//区间赋 0,把 y(全 0 树) 全部贴到 x 上
        if(L <= l && r <= R){
            x = y;
            return;
        }
        int mid = (l + r) >> 1, z = ++cnt;
        t[z] = t[x];
        if(L <= mid) clear(ls(z), ls(y), L, R, l, mid);
        if(R > mid) clear(rs(z), rs(y), L, R, mid + 1, r);
        pushup(x = z);
    }
    
    inline int search(int rt, int l, int r, int val){//线段树上二分,向上找第一个不为 1 的位置
        if(l == r) return l;
        int mid = (l + r) >> 1;
        if(val > mid) return search(rs(rt), mid + 1, r, val);//查找权值在右子树
        if(query(ls(rt), val, mid, l, mid) == mid - val + 1) return search(rs(rt), mid + 1, r, mid + 1);//左子树全为 1 且 val <= mid,到右子树查询
        return search(ls(rt), l, mid, val);//否则在左子树查询
    }
    
    inline bool cmp(int x, int y, int l, int r){
        if(l == r) return t[x].sum < t[y].sum;
        int mid = (l + r) >> 1;
        if(t[rs(x)] == t[rs(y)]) return cmp(ls(x), ls(y), l, mid);
        return cmp(rs(x), rs(y), mid + 1, r);
    }
    
    struct Que{
        int id, rt;
        friend bool operator < (Que a, Que b){
            return cmp(b.rt, a.rt, 0, N - 1);
        }
    };
    
    inline void dijkstra(){
        priority_queue <Que> q;
        for(int i = 1; i <= n; ++i)
            root[i] = inf;
        root[S] = root[0];
        q.push((Que){S, root[S]});
        while(!q.empty()){
            int x = q.top().id;
            q.pop();
            if(vis[x]) continue;
            vis[x] = 1;
            for(int i = head[x]; i; i = edge[i].nxt){
                int y = edge[i].v, rt_x = root[x], res = cnt;
                int pos = search(root[x], 0, N - 1, edge[i].w);
                update(rt_x, 0, N - 1, pos);
                if(edge[i].w < pos) clear(rt_x, root[0], edge[i].w, pos - 1, 0, N - 1);
                if(cmp(rt_x, root[y], 0, N - 1)) pre[y] = x, q.push((Que){y, root[y] = rt_x});
                else cnt = res;
            }
        }
    }
    
    int main(){
        n = read(), m = read();
        for(int i = 1; i <= m; ++i){
            int u = read(), v = read(), w = read();
            add(u, v, w), add(v, u, w);
        }
        S = read(), T = read();
        fac[0] = 1;
        for(int i = 1; i < N; ++i)
            fac[i] = fac[i - 1] * 2 % mod;
        build(root[0], 0, N - 1, 0), build(inf, 0, N - 1, 1);
        dijkstra();
        if(root[T] == inf){
            puts("-1");
            return 0;
        }
        for(int x = T; x != S; x = pre[x]) ans[++path] = x;
        ans[++path] = S;
        printf("%lld
    %d
    ", t[root[T]].sum, path);
        for(int i = path; i >= 1; --i)
            printf("%d ", ans[i]);
        return 0;
    }
    

    [\_EOF\_ ]

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

  • 相关阅读:
    剑指Offer-46.孩子们的游戏(圆圈中最后剩下的数)(C++/Java)
    剑指Offer-45.扑克牌顺子(C++/Java)
    剑指Offer-44.翻转单词顺序列(C++/Java)
    剑指Offer-43.左旋转字符串(C++/Java)
    剑指Offer-42.和为S的两个数字(C++/Java)
    剑指Offer-41.和为S的连续正数序列(C++/Java)
    剑指Offer-40.数组中只出现一次的数字(C++/Java)
    剑指Offer-39.把数组排成最小的数(C++/Java)
    Codeforces Round #316 (Div. 2) D Tree Requests
    URAL 1774 Barber of the Army of Mages (最大流)
  • 原文地址:https://www.cnblogs.com/xixike/p/15484261.html
Copyright © 2011-2022 走看看