1. 程式人生 > >【BZOJ4016】[FJOI2014]最短路徑樹問題

【BZOJ4016】[FJOI2014]最短路徑樹問題

register roi cos com static second 點分治 sort std

【BZOJ4016】[FJOI2014]最短路徑樹問題

題面

bzoj
洛谷

題解

雖然調了蠻久,但是思路還是蠻簡單的2333
把最短路徑樹構出來,然後點分治就好啦
ps:如果樹構萎了,這組數據可以卡掉
代碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath>
#include <algorithm> 
#include <queue>
#include <map>
#include <vector> 
using namespace std; 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (!isdigit(ch) && ch != '-') ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar();
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
    return w * data; 
}
const int MAX_N = 3e4 + 5;
const int MAX_M = 6e4 + 5;
const int INF = 1e9; 
int N, M, K; 
struct Graph { int to, next, cost; } e[MAX_M << 2]; 
int fir1[MAX_N], fir2[MAX_N], e_cnt; 
void clearGraph() {
    memset(fir1, -1, sizeof(fir1)); 
    memset(fir2, -1, sizeof(fir2)); 
    e_cnt = 0;
}
void Add_Edge(int *fir, int u, int v, int w) { e[e_cnt] = (Graph){v, fir[u], w}; fir[u] = e_cnt++; } 
vector<int> vec[MAX_N];
bool vis[MAX_N]; 
bool cmp(int i, int j) { return e[i].to < e[j].to; } 
void dijkstra() { 
    static priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > que;
    static int dis[MAX_N]; 
    fill(&dis[1], &dis[N + 1], INF);
    dis[1] = 0, que.push(make_pair(0, 1)); 
    while (!que.empty()) { 
        pair<int, int> p = que.top(); que.pop(); 
        int x = p.second; 
        if (p.first > dis[x]) continue;
        for (int i = fir1[x]; ~i; i = e[i].next) {
            int v = e[i].to; 
            if (dis[v] + e[i].cost == dis[x]) vec[v].push_back(i ^ 1); 
        } 
        for (int i = fir1[x]; ~i; i = e[i].next) {
            int v = e[i].to; 
            if (dis[x] + e[i].cost < dis[v]) { 
                dis[v] = dis[x] + e[i].cost; 
                que.push(make_pair(dis[v], v)); 
            } 
        } 
    } 
} 
void dfs(int x) { 
    vis[x] = 1; 
    sort(vec[x].begin(), vec[x].end(), cmp); 
    for (int i = 0, sz = vec[x].size(); i < sz; i++) {
        int j = vec[x][i]; if (vis[e[j].to]) continue; 
        Add_Edge(fir2, x, e[j].to, e[j].cost), Add_Edge(fir2, e[j].to, x, e[j].cost); 
        dfs(e[j].to); 
    } 
} 
bool used[MAX_N]; 
int size[MAX_N], dep[MAX_N], dis[MAX_N], centroid, sz, rmx, mx; 
int stk[MAX_N], top = 0; 
int ans1 = 0, ans2 = 0; 
void search_centroid(int x, int fa) { 
    size[x] = 1;
    int mx = 0;
    for (int i = fir2[x]; ~i; i = e[i].next) {
        int v = e[i].to;
        if (v == fa || used[v]) continue; 
        search_centroid(v, x);
        size[x] += size[v];
        mx = max(mx, size[v]); 
    }
    mx = max(mx, sz - size[x]); 
    if (mx < rmx) centroid = x, rmx = mx; 
} 
namespace cpp1 { 
    int bln[MAX_N]; 
    void getans(int x, int fa) {
        if (dep[x] < K - 1) ans1 = max(ans1, bln[K - 1 - dep[x]] + dis[x]); 
        for (int i = fir2[x]; ~i; i = e[i].next) { 
            int v = e[i].to; if (used[v] || v == fa) continue;
            dep[v] = dep[x] + 1; 
            dis[v] = dis[x] + e[i].cost; 
            getans(v, x); 
        } 
    } 
    void getdis(int x, int fa) { 
        stk[++top] = x; bln[dep[x]] = max(bln[dep[x]], dis[x]); 
        for (int i = fir2[x]; ~i; i = e[i].next) { 
            int v = e[i].to; if (used[v] || v == fa) continue; 
            getdis(v, x); 
        } 
    } 
    void Div(int x) { 
        used[x] = 1; top = 0; 
        for (int i = fir2[x]; ~i; i = e[i].next) {
            int v = e[i].to; if (used[v]) continue; 
            dep[v] = 1, dis[v] = e[i].cost; 
            getans(v, 0), getdis(v, 0); 
        }
        ans1 = max(ans1, bln[K - 1]); 
        for (int i = 1; i <= top; i++) bln[dep[stk[i]]] = 0; 
        for (int i = fir2[x]; ~i; i = e[i].next) { 
            int v = e[i].to; if (used[v]) continue; 
            rmx = sz = size[v], centroid = 0; 
            search_centroid(v, 0); 
            Div(centroid); 
        } 
    } 
} 
namespace cpp2 {
    map<pair<int, int>, int> mp; 
    void getans(int x, int fa) { 
        if (dep[x] < K - 1) ans2 += mp[make_pair(ans1 - dis[x], K - 1 - dep[x])]; 
        for (int i = fir2[x]; ~i; i = e[i].next) { 
            int v = e[i].to; if (used[v] || v == fa) continue;
            dep[v] = dep[x] + 1; 
            dis[v] = dis[x] + e[i].cost; 
            getans(v, x); 
        } 
    } 
    void getdis(int x, int fa) {
        mp[make_pair(dis[x], dep[x])]++; 
        for (int i = fir2[x]; ~i; i = e[i].next) { 
            int v = e[i].to; if (used[v] || v == fa) continue; 
            getdis(v, x); 
        } 
    } 
    void Div(int x) { 
        used[x] = 1; 
        for (int i = fir2[x]; ~i; i = e[i].next) {
            int v = e[i].to; if (used[v]) continue; 
            dep[v] = 1, dis[v] = e[i].cost; 
            getans(v, 0), getdis(v, 0); 
        } 
        ans2 += mp[make_pair(ans1, K - 1)]; 
        mp.clear(); 
        for (int i = fir2[x]; ~i; i = e[i].next) { 
            int v = e[i].to; if (used[v]) continue; 
            rmx = sz = size[v], centroid = 0; 
            search_centroid(v, 0); 
            Div(centroid); 
        } 
    }
}
int main () {
    N = gi(), M = gi(), K = gi(); 
    clearGraph(); 
    for (int i = 1; i <= M; i++) { 
        int u = gi(), v = gi(), w = gi();
        Add_Edge(fir1, u, v, w), Add_Edge(fir1, v, u, w); 
    } 
    dijkstra();
    dfs(1); 
    sz = rmx = N; 
    search_centroid(1, 0); 
    cpp1::Div(centroid); 
    memset(used, 0, sizeof(used));
    sz = rmx = N, centroid = 0; 
    search_centroid(1, 0); 
    cpp2::Div(centroid); 
    printf("%d %d\n", ans1, ans2); 
    return 0; 
} 

【BZOJ4016】[FJOI2014]最短路徑樹問題