1. 程式人生 > >CF 464E The Classic Problem

CF 464E The Classic Problem

進行 dijk hid htm operator logs one http 在線

補一補之前聽課時候的題。

考慮使用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; }
View Code

CF 464E The Classic Problem