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 + ;
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的更多相关文章
- [Codeforces 464E] The Classic Problem(可持久化线段树)
[Codeforces 464E] The Classic Problem(可持久化线段树) 题面 给出一个带权无向图,每条边的边权是\(2^{x_i}(x_i<10^5)\),求s到t的最短路 ...
- CodeForces 464E The Classic Problem | 呆克斯歘 主席树维护高精度
题意描述 有一个\(n\)点\(m\)边的无向图,第\(i\)条边的边权是\(2^{a_i}\).求点\(s\)到点\(t\)的最短路长度(对\(10^9 + 7\)取模). 题解 思路很简单--用主 ...
- Codeforces 464E. The Classic Problem
题目大意 给定一张$n$个点, $m$条边的无向图,求$S$ 到$T$的最短路,其中边权都是$2^k$的形式$n,m,k<=10^5$,结果对$10^9+7$取模 题解 大佬好厉害 跑一边dij ...
- Codeforces 464E The Classic Problem (最短路 + 主席树 + hash)
题意及思路 这个题加深了我对主席树的理解,是个好题.每次更新某个点的距离时,是以之前对这个点的插入操作形成的线段树为基础,在O(logn)的时间中造出了一颗新的线段树,相比直接创建n颗线段树更省时间. ...
- Codeforces 464E The Classic Problem(主席树+最短路+哈希,神仙题)
题目链接 题意:给出一张 \(n\) 个点 \(m\) 条边的无向图,第 \(i\) 条边连接 \(u_i,v_i\),边权为 \(2^{w_i}\),求 \(s\) 到 \(t\) 的最短路. \( ...
- Codeforces 464E #265 (Div. 1) E. The Classic Problem 主席树+Hash
E. The Classic Problem http://codeforces.com/problemset/problem/464/E 题意:给你一张无向带权图,求S-T的最短路,并输出路径.边权 ...
- 把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend
//把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend //dp[i][j]:把第i个数转成第j小的数,最小花费 //此题与po ...
- 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 ...
- 【dp/贪心】CF 780 (Div. 3), problem: (C) Get an Even String
Problem - C - Codeforces 难度: 1300 input 6 aabbdabdccc zyx aaababbb aabbcc oaoaaaoo bmefbmuyw output ...
随机推荐
- python编程实例-收集主机信息
收集主机信息: 主机名 ip 操作系统版本osver 服务器厂商vendor 服务器型号:product 服务器序列号:sn CPU型号:cpu_model CPU核数:cpu_num 内存大小:Me ...
- ios --- 调用系统"设置"里的功能(转)
安装后第一次运行软件时,系统会弹出提示用户是否允许软件获取当前位置,如果用户不允许的话,之后运行时系统不会在弹出提示设置,这点很不方便,有个解决办法是给用户一个选项,调出iphone中“设置”定位服务 ...
- 超简单tensorflow入门优化程序&&tensorboard可视化
程序1 任务描述: x = 3.0, y = 100.0, 运算公式 x×W+b = y,求 W和b的最优解. 使用tensorflow编程实现: #-*- coding: utf-8 -*-) im ...
- bzoj 4299 Codechef FRBSUM
定义一个集合的神秘数为不能表示成这个集合的某个子集和的最小正整数,给一个数列,多次求区间神秘数 $n \leq 100000$ sol: 考虑这个神秘数的性质,可以发现,如果神秘数是 $x$,那么 $ ...
- Python 2.7_利用xpath语法爬取豆瓣图书top250信息_20170129
大年初二,忙完家里一些事,顺带有人交流爬取豆瓣图书top250 1.构造urls列表 urls=['https://book.douban.com/top250?start={}'.format(st ...
- 51nod1680 区间求和
有n个数,给定一个k,求所有长度大于等于k的区间中前k大数的总和.这样就比较简单相信大家都会,所以此题要求当k=1~n的总和,即求 ∑nk=1∑n−k+1i=1∑nj=i+k−1 区间前K大和 In ...
- Python 函数之迭代器和生成器
1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可 ...
- Android高仿京东淘宝自动无限循环轮播控件的实现思路和过程
在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的实现思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于 ...
- 自定义mysql函数时报错,[Err] 1418 - This function has none of DETERMINISTIC......
今天在我执行自定义mysql函数的SQL时发生了错误,SQL如下: /** 自定义mysql函数 getChildList */delimiter //CREATE FUNCTION `pengwif ...
- bootstrap简单的签收页面
http://aqvatarius.com/themes/atlant/html/ui-icons.html <%@ Page Language="C#" AutoEvent ...