• CodeForces


    题面

    传送门

    题解

    写的头疼

    先看题, 明显是最短路, 关键是如何保存距离, 毕竟太大了

    而且题目给的就是二进制, 就想到了要拆位,

    一般的拆位用个可持续化 01trie 就好了, 这道题真的毒瘤还是 2进制下1e5 的范围

    那只能可持续化权值线段树了, 好能存路径了, 但问题来了, 毕竟是二进制要考虑进位的

    进位


    先说为什么不能暴力进位, 看着组数据

    100000 99999
    1 2 0
    2 3 1
    ...
    49999 50000 49998
    50000 50001 0
    50000 50002 0
    ...
    50000 100000 0
    1 100000
    

    在点50000之后就是 二进制下整个暴力进位, 每次相当于重新建一棵权值线段树,

    时间复杂度就成了 n * n * logn(n = 5e4)

    50001~100000之间建的线段树空间复杂度为 n * n * logn(n = 5e4)

    时空全爆, 只不过是老题, 没人提供这组hack数据罢了


    什么是二进制进位?

    就是有一段连续的 11111, 你又在其中 + 1, 就进位了

    说白了, 就是清空一段, 在让一个位置 + 1

    而时空复杂度都是 2 * logn = logn

    想象一颗满的权值线段树

    左孩子要进位, 就清空, 复杂度 logn,

    然后让 右孩子 + 1, 如果右孩子的左孩子要进位, 又是一条log, 但是是 log(n/2)的

    不断深入, 最后复杂度应为 logn + log(n/2) + log(n/4) ... < 2logn

    对于右孩子还进位的返回不就完事了, 那是该当前这颗树的祖先的右孩子改进位了

    比较大小

    这里不能直接去比, 看着想 logn 其实不然,

        int cmp(int x, int y, int l, int r) {
            if (tr[x].val == 0 && tr[y].val == 0) return 0;
            else if (tr[x].val == 0) return -1;
            else if (tr[y].val == 0) return 1;
            if (l == r) return tr[x].val < tr[y].val ? -1 : tr[x].val > tr[y].val;
            int mid = l + r >> 1, ans = cmp(tr[x].r, tr[y].r, mid + 1, r);
            return ans ? ans : cmp(tr[x].l, tr[y].l, l, mid);
        }
    

    这就是不断的再找最远的右孩子知道出现某个二进制位置不一样, 复杂明显成线性了

    那咋办, hash 啊, 我怕出错用了两次has, 不过选的好一次就行

    但是随着acm的发展, 正规比赛时卡单has的, 一般双/三哈希卡不住, 这道题数据水了倒是单has能过

    代码

    struct CHT {
        static const int N = 1e5 + 20, mod = 1e9 + 7, mod1 = 13331;
    
        struct Node { int l, r, val, has[2]; } tr[N * 40];
    
        int rt[N], tot, s[2][N] = { {1}, {1} };
    
        void init() {
            rep(i, 1, 1e5 + 16)
                s[0][i] = ((ll)s[0][i - 1] << 1) % mod,
                s[1][i] = ((ll)s[1][i - 1] << 1) % mod1;
        }
    
        void clear(int& x, int y, int l, int r, int L, int R) {
            if (L <= l && r <= R) { x = 0; return; }
            tr[x = ++tot] = tr[y];
            int mid = l + r >> 1;
            if (mid >= L) clear(tr[x].l, tr[y].l, l, mid, L, R);
            if (mid < R) clear(tr[x].r, tr[y].r, mid + 1, r, L, R);
            tr[x].val = tr[tr[x].l].val + tr[tr[x].r].val;
            tr[x].has[0] = ((ll)tr[tr[x].l].has[0] + tr[tr[x].r].has[0]) % mod;
            tr[x].has[1] = ((ll)tr[tr[x].l].has[1] + tr[tr[x].r].has[1]) % mod1;
        }
    
        bool update(int& x, int y, int l, int r, int val) {
            if (tr[y].val == r - l + 1) {
                clear(x, y, l, r, val, r);
                return 1;
            }
            tr[x = ++tot] = tr[y];
            if (l == r) return tr[x].val = 1, tr[x].has[0] = s[0][l], tr[x].has[1] = s[1][l], 0;
            int mid = l + r >> 1, f = 0;
            if (mid >= val) {
                if (update(tr[x].l, tr[y].l, l, mid, val))
                    f = update(tr[x].r, tr[y].r, mid + 1, r, mid + 1);
            }
            else f = update(tr[x].r, tr[y].r, mid + 1, r, val);
            tr[x].has[0] = ((ll)tr[tr[x].l].has[0] + tr[tr[x].r].has[0]) % mod;
            tr[x].has[1] = ((ll)tr[tr[x].l].has[1] + tr[tr[x].r].has[1]) % mod1;
            return tr[x].val = tr[tr[x].l].val + tr[tr[x].r].val, f;
        }
    
        int cmp(int x, int y) {
            if (tr[x].val == 0 && tr[y].val == 0) return 0;
            else if (tr[x].val == 0) return -1;
            else if (tr[y].val == 0) return 1;
            if (tr[tr[x].r].has[0] != tr[tr[y].r].has[0] || tr[tr[x].r].has[1] != tr[tr[y].r].has[1])
                return cmp(tr[x].r, tr[y].r);
            return cmp(tr[x].l, tr[y].l);
        }
    } T;
    
    const int N = 1e5 + 16;
    
    int n, m, _, k;
    
    struct Node { int x, rt; bool operator <(Node a) const { return T.cmp(rt, a.rt) == 1; } };
    
    int main() {
        IOS; cin >> n >> m; vector<vector<PII>> h(n + 1);
        rep(i, 1, m) {
            int u, v, c; cin >> u >> v >> c;
            h[u].pb({ v, c }); h[v].pb({ u, c });
        }
        int s, t; cin >> s >> t; T.init();
        priority_queue<Node> q; q.push({ s, 0 });
        vector<bool> v(n + 1); VI pre(n + 1);
        while (!q.empty()) {
            int x = q.top().x, tmp; q.pop();
            if (v[x]) continue; v[x] = 1;
            if (x == t) break;
            for (auto& e : h[x]) {
                if (v[e.fi]) continue;
                T.update(tmp, T.rt[x], 0, N, e.se);
                if (!T.rt[e.fi] || T.cmp(T.rt[e.fi], tmp) == 1)
                    q.push({ e.fi, T.rt[e.fi] = tmp }), pre[e.fi] = x;
            }
        }
        if (!v[t]) { cout << -1; return 0; } T.init();
        VI ans; for (int i = t; i; ans.pb(i), i = pre[i]);
        cout << T.tr[T.rt[t]].has[0] << '
    ' << ans.size() << '
    ';
        per(i, ans.size() - 1, 0) cout << ans[i] << ' ';
        return 0;
    }
    
  • 相关阅读:
    4个方面教你怎么样成为一名及格的设计师
    CURL函数的GET和POST方式的两种写法(实现ajax跨域调用)
    微信公众平台接口配置问题
    wamp环境PHP安装mongodb扩展
    WAMP 403 Forbidden禁止访问
    PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
    在微信中实现app软件中账号注册的功能实现
    form表单只提交数据而不进行页面跳转的解决方案
    背景图片适配手机屏幕大小的设置方法。。。。。。。。。。。。
    TP中二维数组的遍历输出
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/14103239.html
Copyright © 2020-2023  润新知