[IOI2011]Race
阿新 • • 發佈:2018-11-27
get 統計 等於 sizeof name 自己 href ret 套路
題意
Here
思考
簡要題意:給一棵樹,每條邊有權。求一條簡單路徑,權值和等於 \(K\),且邊的數量最小。
由於這條最小路徑可以是所有路徑中的任意一個,所以所有等於 \(K\) 的路徑我們必須考慮到,關於樹上的路徑統計問題,我們選用點分治。
這樣一想就是點分治裸題了,由於 \(K \leq 1e6\),我們可以開個桶然後套路計算了,對於每顆子樹計算完後再加入答案,避免重復計算(大於 \(K\) 的路徑也可以剪點枝)。
代碼
#include<bits/stdc++.h> using namespace std; const int N = 200020; const int M = 1000010; const int oo = 0x3f3f3f3f; int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x * f; } struct node{ int nxt, to, dis; }edge[N << 1]; int head[N], num; void build(int from, int to, int dis){ edge[++num].nxt = head[from]; edge[num].to = to; edge[num].dis = dis; head[from] = num; } int root, ANS, n, k, sum, vis[N], f[N], sz[N], dist[N], ans[M]; void getroot(int u, int fa){ sz[u] = 1; f[u] = 0; for(int i=head[u]; i; i=edge[i].nxt){ int v = edge[i].to; if(v == fa || vis[v]) continue; getroot(v, u); sz[u] += sz[v]; f[u] = max(f[u], sz[v]); } f[u] = max(f[u], sum - sz[u]); if(f[root] > f[u]) root = u; } void dfs(int u, int fa, int cnt){ if(dist[u] > k) return; ANS = min(ANS, ans[ k - dist[u] ] + cnt); for(int i=head[u]; i; i=edge[i].nxt){ int v = edge[i].to; if(v == fa || vis[v]) continue; dist[v] = dist[u] + edge[i].dis; dfs(v, u, cnt + 1); } } void add(int u, int fa, int cnt){ if(dist[u] > k) return; ans[ dist[u] ] = min(ans[ dist[u] ], cnt); for(int i=head[u]; i; i=edge[i].nxt){ int v = edge[i].to; if(v == fa || vis[v]) continue; add(v, u, cnt + 1); } } void clearx(int u, int fa, int dist){ if(dist > k) return; ans[ dist ] = oo; for(int i=head[u]; i; i=edge[i].nxt){ int v = edge[i].to; if(v == fa || vis[v]) continue; clearx(v, u, edge[i].dis + dist); } } void solve(int u){ vis[u] = 1; ans[0] = 0; for(int i=head[u]; i; i=edge[i].nxt){ int v = edge[i].to; if(vis[v]) continue; dist[v] = edge[i].dis; dfs(v, u, 1); add(v, u, 1); } clearx(u, 0, 0); for(int i=head[u]; i; i=edge[i].nxt){ int v = edge[i].to; if(vis[v]) continue; root = 0; sum = sz[v]; getroot(v, u); solve(root); } } int main(){ f[0] = ANS = oo; memset(ans, 0x3f, sizeof(ans)); n = read(), k = read(); for(int i=1; i<=n-1; i++){ int u, v, d; u = read(), v = read(), d = read(); build(u + 1, v + 1, d); build(v + 1, u + 1, d); } sum = n; root = 0; getroot(1, 0); solve(root); if(ANS != oo) cout << ANS; else puts("-1"); return 0; }
總結
寫完之後 \(T\) 了 \(n\) 回,發現是自己找重心的時候 \(f[]\) 數組沒清零,導致這個復雜度啊,有點點大。以後要記得重置數組,不然都沒法查錯啊這個。
[IOI2011]Race