Codeforces 464E

Chairman of the shortest path tree +

Direct shortest run is the answer, but the right side is too large, but because the right side is $ 2 $ integer power, maintain the right side with the Chairman of the tree.

Maintenance point with the shortest distance of each segment tree weights, each position is $ 0 or $ $ $ 1, a segment tree represents a string of hexadecimal $ 2 $.

The question is how to compare the size of two numbers.

For each node maintains a hash value, when compared to the first query a bit to compare different size, compare the hash value.

Consider modifying carry, violence modifications.

Complexity $ (nlog ^ 2n) O $

#include <bits/stdc++.h>
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<data> 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

 

Guess you like

Origin www.cnblogs.com/2-321414133115/p/11368820.html
Recommended