Codeforces 464E

主席树+最短路

直接跑最短路就是答案,但是边权过大,但是由于边权是$2$的整数次幂,用主席树维护边权。

用权值线段树维护每个点的最短距离,每个位置为$0$或$1$,一棵线段树表示一个$2$进制串。

问题在于如何比较两个数的大小。

对于每个节点维护哈希值,比较时查询第一个不同的位来比较大小,比较哈希值即可。

修改考虑进位,暴力修改即可。

复杂度$O(nlog^2n)$

#include 
using 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;
}
View Code

 

转载于:https://www.cnblogs.com/2-321414133115/p/11368820.html

你可能感兴趣的:(Codeforces 464E)