【BZOJ4016】[FJOI2014]最短路徑樹問題
阿新 • • 發佈:2019-01-16
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]最短路徑樹問題