CF464E The Classic Problem
https://www.luogu.com.cn/problem/CF464E
晚修结束前十分钟打开,想了一会没半点思路
杨队过来一眼秒了,wtcl
考虑直接跑dijkstra, 然后高精度加法
这样加一次是 O ( n 2 ) O(n^2) O(n2)的,显然会寄
那么考虑每次只会往一个位置上加一,所以可以继承上一个点,然后区间推平,再单点加一
用主席数维护dis即可
然后再维护一个hash值来比较大小,树上二分一个最长的前缀哈希值相等,然后比较下一位即可
时间复杂度两个log,空间一个log,巨大麻烦题
#include<bits/stdc++.h>
#define ll long long
#define N 400050
#define mod 1000000007
#define ull unsigned long long
#define ls (a[rt].l)
#define rs (a[rt].r)
using namespace std;
const int lim = 100032;
ull ha[N];
inline int rd() {
register int x = 0; char ch = getchar();
for(; ch < '0' || ch > '9';) ch = getchar();
for(; ch >= '0' && ch <= '9';) x = (x << 3) + (x << 1) + (ch - 48), ch = getchar();
return x;
}
void pred() {
srand(1145141919810ll);
for(int i = 0; i <= lim; i ++) ha[i] = ((1ll << 45) * rand()) | ((1ll << 30) * rand()) | ((1ll << 15) * rand()) | rand();
}
struct A {
int l, r, o;
ull ha;
} a[N * 32];
void update(int rt) {
a[rt].ha = a[ls].ha ^ a[rs].ha;
a[rt].o = a[ls].o | a[rs].o;
}
int tot;
void build(int &rt, int l, int r) {
rt = ++ tot;
if(l == r) {
a[rt].o = 1; a[rt].ha = ha[l];
return ;
}
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
update(rt);
}
void change(int lrt, int &rt, int l, int r, int x, int o) {
rt = ++ tot;
if(lrt) a[rt] = a[lrt];
if(l == r) {
a[rt].o = o, a[rt].ha = o * ha[l];
return ;
}
int mid = (l + r) >> 1;
if(x <= mid) change(a[lrt].l, ls, l, mid, x, o);
else change(a[lrt].r, rs, mid + 1, r, x, o);
update(rt);
}
int query(int rt, int l, int r, int x) {
if(!a[rt].o || !rt) return 0;
if(l == r) return 1;
int mid = (l + r) >> 1;
if(x <= mid) return query(ls, l, mid, x);
return query(rs, mid + 1, r, x);
}
void pluss(int &x, int y) {
while(query(x, 0, lim, y)) change(x, x, 0, lim, y, 0), y ++;
change(x, x, 0, lim, y, 1);
}
int cmpp(int x, int y, int l, int r) {
if(l == r || !a[x].o || !a[y].o) return a[x].o <= a[y].o;
int mid = (l + r) >> 1;
if(a[a[x].r].ha == a[a[y].r].ha) return cmpp(a[x].l, a[y].l, l, mid);
return cmpp(a[x].r, a[y].r, mid + 1, r);
}
int cmp(int x, int y) {
return cmpp(x, y, 0, lim);
}
struct edge {
int v, nxt, c;
} e[N << 1];
int p[N], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void insert(int u, int v, int c) {
e[eid].v = v;
e[eid].nxt = p[u];
e[eid].c = c;
p[u] = eid ++;
}
int S, T, n, m, rt[N], vis[N], pre[N], sta[N], dis[N], pw[N];
struct Q {
int x, y;
bool operator < (const Q &o) const {
return !cmp(y, o.y);
}
};
priority_queue<Q> q;
void dij() {
build(rt[0], 0, lim);
pw[0] = 1;
for(int i = 1; i <= lim; i ++) pw[i] = (pw[i - 1] * 2) % mod;
for(int i = 1; i <= n; i ++) if(i != S) rt[i] = rt[0];
q.push((Q){S, rt[0]});
while(q.size()) {
int u = q.top().x; q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v, c = e[i].c;
int x = rt[u]; pluss(x, c);
if(cmp(x, rt[v])) {
rt[v] = x;
pre[v] = u;
dis[v] = (dis[u] + pw[c]) % mod;
q.push((Q){v, rt[v]});
}
}
}
}
int main() {
pred();
init();
n = rd(), m = rd();
for(int i = 1; i <= m; i ++) {
int u, v, c;
u = rd(), v = rd(), c = rd();
insert(u, v, c), insert(v, u, c);
}
S = rd(), T = rd();
dij();
if(!vis[T]) {
printf("-1");
return 0;
}
printf("%d\n", dis[T]);
int gs = 0;
while(T != S) sta[++ gs] = T, T = pre[T];
sta[++ gs] = S;
printf("%d\n", gs);
while(gs) printf("%d ", sta[gs --]);
return 0;
}