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

考虑使用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 + ;
const int P = 1e9 + ; int n, m, st, ed, lim = , bin[N << ];
int tot = , head[N], pre[N]; struct Edge {
int to, nxt, val;
} e[N << ]; 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 = ; char ch = ; int op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} namespace PSegT {
struct SegNode {
int lc, rc, w;
} s[N * ]; 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 + , 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 ^ ;
return s[y].w;
} int res;
if(pos > mid) res = modify(s[x].rc, mid + , 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 + , r, mid + , s[y].rc);
} s[x].w = (1LL * s[s[x].rc].w * bin[mid - l + ] % 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, , 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 + );
printf("%d ", x);
} inline void out() {
printf("%d\n", s[root[ed]].w);
dfs(ed, );
printf("\n");
exit();
} int main() {
read(n), read(m);
for(int x, y, v, i = ; i <= m; i++) {
read(x), read(y), read(v);
add(x, y, v), add(y, x, v);
chkMax(lim, v);
}
lim += ;
read(st), read(ed); for(int i = bin[] = ; i <= lim; i++)
bin[i] = 1LL * bin[i - ] * % P; nodeCnt = ;
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, , lim, e[i].val, root[now.x]);
if(!root[y] || cmp(root[y], , lim, v)) {
root[y] = v;
Q.push((Node) {y, root[y]});
pre[y] = now.x;
}
}
} puts("-1");
return ;
}

CF 464E The Classic Problem的更多相关文章

  1. [Codeforces 464E] The Classic Problem(可持久化线段树)

    [Codeforces 464E] The Classic Problem(可持久化线段树) 题面 给出一个带权无向图,每条边的边权是\(2^{x_i}(x_i<10^5)\),求s到t的最短路 ...

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

    题意描述 有一个\(n\)点\(m\)边的无向图,第\(i\)条边的边权是\(2^{a_i}\).求点\(s\)到点\(t\)的最短路长度(对\(10^9 + 7\)取模). 题解 思路很简单--用主 ...

  3. Codeforces 464E. The Classic Problem

    题目大意 给定一张$n$个点, $m$条边的无向图,求$S$ 到$T$的最短路,其中边权都是$2^k$的形式$n,m,k<=10^5$,结果对$10^9+7$取模 题解 大佬好厉害 跑一边dij ...

  4. Codeforces 464E The Classic Problem (最短路 + 主席树 + hash)

    题意及思路 这个题加深了我对主席树的理解,是个好题.每次更新某个点的距离时,是以之前对这个点的插入操作形成的线段树为基础,在O(logn)的时间中造出了一颗新的线段树,相比直接创建n颗线段树更省时间. ...

  5. Codeforces 464E The Classic Problem(主席树+最短路+哈希,神仙题)

    题目链接 题意:给出一张 \(n\) 个点 \(m\) 条边的无向图,第 \(i\) 条边连接 \(u_i,v_i\),边权为 \(2^{w_i}\),求 \(s\) 到 \(t\) 的最短路. \( ...

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

    E. The Classic Problem http://codeforces.com/problemset/problem/464/E 题意:给你一张无向带权图,求S-T的最短路,并输出路径.边权 ...

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

    //把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend //dp[i][j]:把第i个数转成第j小的数,最小花费 //此题与po ...

  8. cf 633B A trivial problem

    Mr. Santa asks all the great programmers of the world to solve a trivial problem. He gives them an i ...

  9. 【dp/贪心】CF 780 (Div. 3), problem: (C) Get an Even String

    Problem - C - Codeforces 难度: 1300 input 6 aabbdabdccc zyx aaababbb aabbcc oaoaaaoo bmefbmuyw output ...

随机推荐

  1. windows下安装 redis并开机自启动

    1,redis官方下载地址:https://redis.io/download,redis 64位下载地址:https://github.com/ServiceStack/redis-windows, ...

  2. Python&&ipython安装注意事项

    yum源里没有,需要先安装一个epel-release这个包,它提供的yum源里有,然后在yum install python-pip.ftp://ftp.muug.mb.ca/mirror/cent ...

  3. Ajax与后台的交互

    Ajax Java 交互 jsp代码 <%@ page language="java" import="java.util.*" pageEncoding ...

  4. 剑指offer--16.数组中重复的数字

    时间限制:1秒 空间限制:32768K 热度指数:198342 本题知识点: 数组 题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复 ...

  5. python主函数

    Python的人会很不习惯Python没有main主函数. 这里简单的介绍一下,在Python中使用main函数的方法 #hello.py def foo(): str="function& ...

  6. docker下安装 Oracle11gR2

    这是第二次安装,在第一次安装过程部分内容参考自如下: http://blog.sina.com.cn/s/blog_d840ff330102v4j0.html docker下oracle11g安装 h ...

  7. [独孤九剑]Oracle知识点梳理(十)%type与%rowtype及常用函数

    本系列链接导航: [独孤九剑]Oracle知识点梳理(一)表空间.用户 [独孤九剑]Oracle知识点梳理(二)数据库的连接 [独孤九剑]Oracle知识点梳理(三)导入.导出 [独孤九剑]Oracl ...

  8. LeetCode Binary Tree Tilt

    原题链接在这里:https://leetcode.com/problems/binary-tree-tilt/description/ 题目: Given a binary tree, return ...

  9. hdu5542 The Battle of Chibi[DP+BIT]

    求给定序列中长度为M的上升子序列个数.$N,M<=1000$. 很容易想到方法.$f[i,j]$表示以第$i$个数结尾,长度为$j$的满足要求子序列个数.于是转移也就写出来了$f[i][j]+= ...

  10. tp验证码

    一.生成验证码 1.commonController.class.php class CommonController extends Controller{ public function getV ...