Codeforces

Luogu

分析

显然可以直接 Dijkstra,问题在于实现一个支持加法和比较大小的优秀的高精度。设比较大小的复杂度是 $\mathcal{O}(\alpha)$,加法的复杂度是 $\mathcal{O}(\beta)$,则 Dijkstra 的复杂度为 $\mathcal{O}(\alpha(n+m)\log n+\beta m)$。

因为边权全部是 $2$ 的幂,因此考虑拿线段树维护每个二进制位。这样子加法就只要二分出一段 $1$ 并将其赋值为 $0$,再在高位填上一个 $1$,比较大小可以在线段树上二分出 LCP 然后比较低位。因此我们需要在线段树上维护区间和和区间哈希值(直接自然溢出啥事没有.jpg)。这样子比较大小是 $\mathcal{O}(\log n)$ 的,加法是 $\mathcal{O}(\log^2 n)$ 的,因此总复杂度 $\mathcal{O}(n\log^2 n)$。

因为每个节点的 $dis$ 都是一棵线段树,而我们又不能直接在原来的线段树上修改,所以需要可持久化线段树。

因为若干个 $2^{10^6}$ 加起来显然是大于 $2^{10^6}$ 的,所以数组要略微开大一点。

代码

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=100200+10,L=100200;
const int BASE=19491001;
const int mod=1e9+7;

int n,m,S,T;
struct edge { int v,w,nxt; } e[N<<1];
int head[N];
void addEdge(int u,int v,int w) {
    static int cnt=0;
    e[++cnt]=(edge){v,w,head[u]},head[u]=cnt;
}

ull pw[N]; int pw2[N];

#define ls(o) t[o].ls
#define rs(o) t[o].rs
int rt[N],tot=0;
struct node { int sum,val,ls,rs; ull hash; } t[N*150];
void pushup(int o) {
    t[o].sum=t[ls(o)].sum+t[rs(o)].sum;
    t[o].val=(t[ls(o)].val+t[rs(o)].val)%mod;
    t[o].hash=t[ls(o)].hash+t[rs(o)].hash;
}
void build(int& o,int l,int r) {
    if (!o) o=++tot;
    if (l==r) return;
    int mid=(l+r)>>1;
    build(ls(o),l,mid),build(rs(o),mid+1,r);
    pushup(o);
}
void modify(int& o,int l,int r,int p) {
    t[++tot]=t[o],o=tot;
    if (l==r) {
        t[o].sum=1,t[o].val=pw2[l],t[o].hash=pw[l];
        return;
    }
    int mid=(l+r)>>1;
    if (p<=mid) modify(ls(o),l,mid,p);
    else modify(rs(o),mid+1,r,p);
    pushup(o);
}
bool cmp(int x,int y,int l,int r) {
    if (l==r) return t[x].sum>t[y].sum;
    int mid=(l+r)>>1;
    if (t[rs(x)].hash==t[rs(y)].hash) return cmp(ls(x),ls(y),l,mid);
    else return cmp(rs(x),rs(y),mid+1,r);
}
void assign(int& o,int z,int l,int r,int ql,int qr) {
    if (ql<=l&&r<=qr) { o=z; return; }
    t[++tot]=t[o],o=tot;
    int mid=(l+r)>>1;
    if (ql<=mid) assign(ls(o),ls(z),l,mid,ql,qr);
    if (qr>mid) assign(rs(o),rs(z),mid+1,r,ql,qr);
    pushup(o);
}
int query(int o,int l,int r,int ql,int qr) {
    if (ql<=l&&r<=qr) return t[o].sum;
    int mid=(l+r)>>1,res=0;
    if (ql<=mid) res+=query(ls(o),l,mid,ql,qr);
    if (qr>mid) res+=query(rs(o),mid+1,r,ql,qr);
    return res;
}
#undef ls
#undef rs

void add(int& o,int p) {
    if (!query(o,0,L,p,p)) { modify(o,0,L,p); return; }
    int l=p,r=L;
    while (l<r) {
        int mid=(l+r+1)>>1;
        if (query(o,0,L,p,mid)==mid-p+1) l=mid;
        else r=mid-1;
    }
    assign(o,rt[0],0,L,p,l),modify(o,0,L,l+1);
}

struct Hnode { int u,d; };
bool operator <(Hnode a,Hnode b) { return cmp(a.d,b.d,0,L); }
priority_queue<Hnode> Q;
int vis[N],lst[N];
void dijkstra() {
    build(rt[0],0,L),rt[S]=rt[0]; Q.push((Hnode){S,rt[S]});
    while (!Q.empty()) {
        int u=Q.top().u; Q.pop();
        if (vis[u]) continue; vis[u]=1;
        for (int i=head[u];i;i=e[i].nxt) {
            int v=e[i].v,w=e[i].w; if (vis[v]) continue;
            int t=rt[u]; add(t,w);
            if (!lst[v]||cmp(rt[v],t,0,L))
                lst[v]=u,rt[v]=t,Q.push((Hnode){v,rt[v]});
        }
    }
}

vector<int> ans;
int main() {
    n=read(),m=read();
    for (int i=1;i<=m;++i) {
        int u=read(),v=read(),w=read();
        addEdge(u,v,w),addEdge(v,u,w);
    }
    pw[0]=pw2[0]=1;
    for (int i=1;i<=L;++i) pw[i]=pw[i-1]*BASE;
    for (int i=1;i<=L;++i) pw2[i]=2ll*pw2[i-1]%mod;
    S=read(),T=read();
    dijkstra();
    if (!vis[T]) { puts("-1"); return 0; }
    printf("%d\n",t[rt[T]].val);
    for (int i=T;i;i=lst[i]) ans.emplace_back(i);
    reverse(ans.begin(),ans.end());
    printf("%lu\n",ans.size());
    for (int i:ans) printf("%d ",i); puts("");
    return 0;
}
最后修改:2020 年 07 月 31 日 08 : 11 PM