• BZOJ 4016: [FJOI2014]最短路径树问题( 最短路 + 点分治 )


    先跑出最短路的图, 然后对于每个点按照序号从小到大访问孩子, 就可以搞出符合题目的树了. 然后就是经典的点分治做法了. 时间复杂度O(M log N + N log N)

    ----------------------------------------------------------------------------

    #include<queue>
    #include<cctype>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    const int maxn = 30009;
    const int INF = 0X3F3F3F3F;
     
    inline int getint() {
    char c = getchar();
    for(; !isdigit(c); c = getchar());
    int ret = 0;
    for(; isdigit(c); c = getchar())
    ret = ret * 10 + c - '0';
    return ret;
    }
     
    int N, K, n = 0;
    int d[maxn], seq[maxn << 1], w[maxn << 1], r[maxn << 1], L[maxn], R[maxn];
    bool vis[maxn];
     
    inline void Max(int &x, int t) {
    if(t > x) x = t;
    }
     
    struct edge {
    int t, w;
    bool f;
    edge* n;
    } E[maxn << 2], *pt = E, *H[maxn];
     
    inline void AddEdge(int u, int v, int w) {
    pt->f = 0, pt->t = v, pt->w = w, pt->n = H[u], H[u] = pt++;
    }
     
    struct node {
    int n, w;
    node(int _n, int _w) : n(_n), w(_w) {
    }
    bool operator < (const node &o) const {
    return w > o.w;
    }
    };
     
    priority_queue<node> q;
     
    void Dijkstra() {
    for(int i = 0; i < N; i++) d[i] = INF;
    d[0] = 0;
    q.push(node(0, 0));
    while(!q.empty()) {
    node o = q.top(); q.pop();
    if(d[o.n] != o.w) continue;
    for(edge* e = H[o.n]; e; e = e->n) if(d[e->t] > d[o.n] + e->w) {
    d[e->t] = d[o.n] + e->w;
    q.push(node(e->t, d[e->t]));
    }
    }
    }
     
    void Init() {
    N = getint();
    int m = getint();
    K = getint();
    while(m--) {
    int u = getint() - 1, v = getint() - 1, w = getint();
    AddEdge(u, v, w), AddEdge(v, u, w);
    }
    }
     
    namespace F {
    edge E[maxn << 1], *pt = E, *H[maxn];
    bool vis[maxn];
    int L[maxn], cnt[maxn], sz[maxn];
    int Root, mn, n, ans, tot;
    inline void AddEdge(int u, int v, int w) {
    pt->t = v, pt->w = w, pt->n = H[u], H[u] = pt++;
    }
    void DFS(int x, int fa = -1) {
    int mx = 0;
    sz[x] = 1;
    for(edge* e = H[x]; e; e = e->n) if(e->t != fa && !vis[e->t]) {
    DFS(e->t, x);
    sz[x] += sz[e->t];
    Max(mx, sz[e->t]);
    }
    Max(mx, n - sz[x]);
    if(mx < mn)
    mn = mx, Root = x;
    }
    void dfs_upd(int x, int fa, int d, int c) {
    if(c >= K) return;
    if(cnt[K - c - 1] && d + L[K - c - 1] > ans)
    ans = d + L[K - c - 1], tot = cnt[K - c - 1];
    else if(d + L[K - c - 1] == ans)
    tot += cnt[K - c - 1];
    c++;
    for(edge* e = H[x]; e; e = e->n)
    if(e->t != fa && !vis[e->t]) dfs_upd(e->t, x, d + e->w, c);
    }
    void dfs_add(int x, int fa, int d, int c) {
    if(c >= K) return;
    if(d > L[c])
    L[c] = d, cnt[c] = 1;
    else if(d == L[c])
    cnt[c]++;
    c++;
    for(edge* e = H[x]; e; e = e->n)
    if(e->t != fa && !vis[e->t]) dfs_add(e->t, x, d + e->w, c);
    }
    void Solve(int x) {
    mn = maxn, DFS(x);
    for(int i = 0; i <= sz[x]; i++) L[i] = cnt[i] = 0;
    x = Root;
    cnt[0] = 1;
    for(edge* e = H[x]; e; e = e->n) if(!vis[e->t]) {
    dfs_upd(e->t, x, e->w, 1);
    dfs_add(e->t, x, e->w, 1);
    }
    DFS(x);
    vis[x] = true;
    for(edge* e = H[x]; e; e = e->n)
    if(!vis[e->t]) n = sz[e->t], Solve(e->t);
    }
    void Work() {
    for(int i = 0; i < N; i++)
    vis[i] = false;
    ans = tot = 0;
    n = N;
    Solve(0);
    printf("%d %d ", ans, tot);
    }
    }
     
    bool Cmp(const int &l, const int &r) {
    return seq[l] < seq[r];
    }
     
    void dfs(int x) {
    seq[L[x] = ++n] = x;
    r[n] = n;
    vis[x] = true;
    for(edge* e = H[x]; e; e = e->n) if(!vis[e->t] && d[e->t] == d[x] + e->w) {
    seq[++n] = e->t;
    w[n] = e->w;
    r[n] = n;
    }
    R[x] = n;
    sort(r + L[x], r + R[x] + 1, Cmp);
    for(int i = L[x]; i <= R[x]; i++) if(!vis[seq[r[i]]]) {
    F::AddEdge(x, seq[r[i]], w[r[i]]);
    F::AddEdge(seq[r[i]], x, w[r[i]]);
    dfs(seq[r[i]]);
    }
    }
     
    void Build() {
    for(int i = 0; i < N; i++) vis[i] = false;
    dfs(0);
    }
     
    int main() {
    Init();
    Dijkstra();
    Build();
    F::Work();
    return 0;
    }

    ---------------------------------------------------------------------------- 

  • 相关阅读:
    MyBatis入门
    Java JDBC
    Spring MVC
    Java内存模型
    Java日志
    Java I/O模型
    Java异常处理
    Java泛型设计
    Java反射
    Java代理
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5179125.html
Copyright © 2020-2023  润新知