主席树+最短路
直接跑最短路就是答案,但是边权过大,但是由于边权是$2$的整数次幂,用主席树维护边权。
用权值线段树维护每个点的最短距离,每个位置为$0$或$1$,一棵线段树表示一个$2$进制串。
问题在于如何比较两个数的大小。
对于每个节点维护哈希值,比较时查询第一个不同的位来比较大小,比较哈希值即可。
修改考虑进位,暴力修改即可。
复杂度$O(nlog^2n)$
#includeusing namespace std; const int maxn = 1e5 + 1005, P = 1e9 + 7; int n, m, cnt = 1, S, T, mx; struct edge { int nxt, to, w; } e[maxn * 2]; vector<int> path; int h[maxn], rt[maxn], f[maxn], pree[maxn * 2]; void link(int u, int v, int w) { e[++cnt].nxt = h[u]; h[u] = cnt; e[cnt].to = v; e[cnt].w = w; } namespace { int Pool = 0; struct node { int lc, rc, h; } t[maxn * 150]; int update(int l, int r, int &x, int y, int p) { t[x = ++Pool] = t[y]; if(l == r) { t[x].h = t[y].h ^ 1; return t[x].h; } int mid = l + r >> 1, ret; if(p <= mid) { ret = update(l, mid, t[x].lc, t[y].lc, p); if(!ret) ret = update(mid + 1, r, t[x].rc, t[y].rc, mid + 1); } else ret = update(mid + 1, r, t[x].rc, t[y].rc, p); t[x].h = (1LL * t[t[x].rc].h * f[mid - l + 1] % P + t[t[x].lc].h) % P; return ret; } } bool cmp(int l, int r, int x, int y) { if(l == r) return t[x].h > t[y].h; int mid = l + r >> 1; if(t[t[x].rc].h == t[t[y].rc].h) return cmp(l, mid, t[x].lc, t[y].lc); return cmp(mid + 1, r, t[x].rc, t[y].rc); } struct data { int rt, x; data() {} data(int _rt, int _x) : rt(_rt), x(_x) {} bool friend operator < (const data &a, const data &b) { return cmp(0, mx, a.rt, b.rt); } }; int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= m; ++i) { int u, v, w; scanf("%d%d%d", &u, &v, &w); link(u, v, w); link(v, u, w); mx = max(mx, w); } mx += 100; f[0] = 1; for(int i = 1; i < maxn; ++i) f[i] = 1LL * f[i - 1] * 2 % P; priority_queue q; scanf("%d%d", &S, &T); q.push(data(0, S)); while(!q.empty()) { data t = q.top(); q.pop(); int u = t.x; if(t.rt != rt[u]) continue; if(t.x == T) break; for(int i = h[u]; i; i = e[i].nxt) { int RT = 0; update(0, mx, RT, t.rt, e[i].w); if(!rt[e[i].to] || cmp(0, mx, rt[e[i].to], RT)) { rt[e[i].to] = RT; pree[e[i].to] = i; q.push(data(RT, e[i].to)); } } } if(!pree[T] && S != T) return puts("-1"); int ans = 0, x = T; while(x != S) { ans = (ans + f[e[pree[x]].w]) % P; path.push_back(x); x = e[pree[x] ^ 1].to; } path.push_back(S); reverse(path.begin(), path.end()); printf("%d\n%d\n", ans, path.size()); for(int i = 0; i < path.size(); ++i) printf("%d ", path[i]); return 0; }