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;
}
posted @ 2021-12-04 08:03  lahlah  阅读(62)  评论(0编辑  收藏  举报