CF 464E The Classic Problem

补一补之前听课时候的题。

考虑使用dij算法求最短路,因为边权存不下,所以考虑用主席树维护二进制位,因为每一次都只会在一个位置进行修改,所以可以暴力进位,这样均摊复杂度是对的。

《算法导论》给了证明:对于一个有$k$位的二进制计数器,假设每一次都从第0位$+1$,那么我们发现执行$n$次加法之后,发现第零位会变$\left \lfloor \frac{n}{1} \right \rfloor$次,第一位会变$\left \lfloor \frac{n}{2} \right \rfloor$次...而第$n$位会变$\left \lfloor \frac{n}{2^n} \right \rfloor$次,这样子所有的操作次数就相当于$\sum_{i = 0}^{k - 1}\left \lfloor \frac{i}{2^i} \right \rfloor < n * \sum_{i = 0}^{\infty}\frac{1}{2^i} = 2n$,所以最坏情况下的时间为$O(n)$,每一次操作的均摊时间复杂度为$O(n) / n = O(1)$。

这样子只需要借助主席树写一个时间为$O(log)$的$cmp$函数就可以用堆优化dijkskra了,遇到进位就在线段树上暴力搞一搞,反正复杂度是对的。

数太大了直接用题目中给的$seed = 2, Mod = 1e9 + 7$的哈希哈希一下就好了。

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

感觉就像是对着大佬的题解抄了一遍。

Code:

#include <cstdio>
#include <cstring>
#include <queue>
#include <cstdlib>
using namespace std;

const int N = 1e5 + 5;
const int P = 1e9 + 7;

int n, m, st, ed, lim = 0, bin[N << 1];
int tot = 0, head[N], pre[N];

struct Edge {
    int to, nxt, val;
} e[N << 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;
}

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;
}

inline void chkMax(int &x, int y) {
    if(y > x) x = y;
}

namespace PSegT {
    struct SegNode {
        int lc, rc, w;
    } s[N * 120];

    int nodeCnt, root[N];

    #define mid ((l + r) >> 1)

    bool cmp(int x, int l, int r, int y) {
        if(l == r) return s[x].w > s[y].w;
        if(s[s[x].rc].w == s[s[y].rc].w) return cmp(s[x].lc, l, mid, s[y].lc);
        else return cmp(s[x].rc, mid + 1, r, s[y].rc);
    }

    bool modify(int &x, int l, int r, int pos, int y) {
        s[x = ++nodeCnt] = s[y];
        if(l == r) {
            s[x].w = s[y].w ^ 1;
            return s[y].w;
        }

        int res;
        if(pos > mid) res = modify(s[x].rc, mid + 1, r, pos, s[y].rc);
        else {
            res = modify(s[x].lc, l, mid, pos, s[y].lc);
            if(res) res = modify(s[x].rc, mid + 1, r, mid + 1, s[y].rc);
        }

        s[x].w = (1LL * s[s[x].rc].w * bin[mid - l + 1] % P + s[s[x].lc].w) % P;
        return res;
    }

} using namespace PSegT;

struct Node {
    int x, rt;

    bool operator < (const Node &oth) const {
        return cmp(rt, 0, lim, oth.rt);
    }

};
priority_queue <Node> Q;

void dfs(int x, int dep) {
    if(x == st) {
        printf("%d\n%d ", dep, x);
        return;
    }

    dfs(pre[x], dep + 1);
    printf("%d ", x);
}

inline void out() {
    printf("%d\n", s[root[ed]].w);
    dfs(ed, 1);
    printf("\n");
    exit(0);
}

int main() {
    read(n), read(m);
    for(int x, y, v, i = 1; i <= m; i++) {
        read(x), read(y), read(v);
        add(x, y, v), add(y, x, v);
        chkMax(lim, v);
    }
    lim += 100;
    read(st), read(ed);

    for(int i = bin[0] = 1; i <= lim; i++)
        bin[i] = 1LL * bin[i - 1] * 2 % P;

    nodeCnt = 0;
    Q.push((Node) {st, root[st]});
    for(; !Q.empty(); ) {
        Node now = Q.top(); Q.pop();
        if(now.rt != root[now.x]) continue;
        if(now.x == ed) out();
        for(int i = head[now.x]; i; i = e[i].nxt) {
            int y = e[i].to, v;
            modify(v, 0, lim, e[i].val, root[now.x]);
            if(!root[y] || cmp(root[y], 0, lim, v)) {
                root[y] = v;
                Q.push((Node) {y, root[y]});
                pre[y] = now.x;
            }
        }
    }

    puts("-1");
    return 0;
}

原文地址:https://www.cnblogs.com/CzxingcHen/p/9565284.html

时间: 2024-11-01 16:37:34

CF 464E The Classic Problem的相关文章

CodeForces 464E The Classic Problem | 呆克斯歘 主席树维护高精度

题意描述 有一个\(n\)点\(m\)边的无向图,第\(i\)条边的边权是\(2^{a_i}\).求点\(s\)到点\(t\)的最短路长度(对\(10^9 + 7\)取模). 题解 思路很简单--用主席树维护每个点的\(dis\).因为每次更新某个点\(v\)的\(dis_v\)的时候,新的\(dis_v\)都是某个点\(u\)的\(dis_u + 2^{w_{u, v}}\),相当于在原先\(u\)对应的主席树基础上修改,得到新的一棵主席树,作为\(v\)对应的主席树. 主席树(线段树)维护二

Codeforces 464E #265 (Div. 1) E. The Classic Problem 主席树+Hash

E. The Classic Problem http://codeforces.com/problemset/problem/464/E 题意:给你一张无向带权图,求S-T的最短路,并输出路径.边权为2^xi.xi≤105,n≤105,m≤105. 想法:边权太大了,可以用数组按二进制存下来.带高精度跑太费事了. 观察一下,这里距离的更新:c=(a,b),用dis[a]更新dis[b] ①dis[b][c]=0,直接赋为1.只有一个数字改变. ②dis[b][c]=1,需要进位.考虑极端情况数

把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend

1 //把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend 2 //dp[i][j]:把第i个数转成第j小的数,最小花费 3 //此题与poj 3666相似 a[i]转换成a[i]-i 4 5 #include <iostream> 6 #include <cstdio> 7 #include <cstdlib> 8 #include <algorithm> 9 #include <

CF 713C Sonya and Problem Wihtout a Legend(DP)

原版题意:给定一个序列,每次操作给其中一个数$+1$或$-1$,问最少需要多少操作使得整个序列为不下降序列. 题解:不下降序列最后修改完成后的各个数一定是原序列中的某一个数.关于这个的理解看到网上的一个解释:原序列,从左到右扫过去,如果左边的大于右边的,要么左边的减掉使其等于右边的,要么右边的加上使其等于左边的. $dp[i][j]$:前i个数以原序列排序后的第j个数为结尾需要的最少操作. 状态转移方程:$dp[i][j]=min(dp[i][j-1],dp[i-1][j]+abs(a[i]-b

CF GYM 100548 The Problem Needs 3D Arrays(2014ACM西安现场赛Problem C)

ProblemC. The Problem Needs 3D Arrays Description A permutation is asequence of integers p1, p2, . . . , pn,consisting of n distinct positive integers and each of them does notexceed n. Assume that r(S) of sequence S denotes the number ofinversions i

CF GYM 100548 The Problem to Make You Happy(2014ACM西安现场赛Problem H)

ProblemH. The Problem to Make You Happy Description Alice and Bob aregood friends, as in every other storyline. One day Alice and Bob areplaying an interesting game. The game is played on a directedgraph with n vertices and m edges, Alice and Bob hav

Cracking the coding interview汇总目录

很久之前刷的CTCI的题目,都快忘记了,做个分类汇总,再重新好好复习一遍. Chapter 1 | Arrays and Strings 1.1 Implement an algorithm to determine if a string has all unique characters. What if you can not use additional data structures? 1.2 Write code to reverse a C-Style String. (C-Str

分治题目 wikioi 1688 逆序数组 算导2-4

解题报告 算导上给了提示 用归并排序的代码进行修改来实现 思考后不难看出 归并排序的合并(merge)过程中 对数据进行了比较 1)如果数组L 的当前某元素大于数组R的当前元素,那么 由于L数组是有序的(升序) 因此 L数组当前元素以及他后面的所有元素都与R数组构成逆序对 2)我们的排序并不影响逆序对的数量 因为排序的时候不会改变当前被排序的数据和还未被处理的数据之间的位置关系(就是说 排序前在未处理元素左边的数据,排序后还在未处理元素左边,所以不改变逆序对的数量) 严格的证明待以后学好算法导论

CTCI 3.4

In the classic problem of the Towers of Hanoi, you have 3 towers and Ndisks of different sizes which can slide onto any tower.The puzzle starts with disks sorted in ascending order of size from top to bottom (i.e., each disk sits on top of an even la