1. 程式人生 > >bzoj2599: [IOI2011]Race

bzoj2599: [IOI2011]Race

getch 點分治 記得 void num AS IV 合並 code

題目鏈接

bzoj2599: [IOI2011]Race

題解

點分治,用t[k]表示子樹中距離root為k 的最小邊路徑
轉移時先與前邊子樹和合並更新答案,然後更新距離父節點最優值,這樣就保證不在同一子樹內了
每次分層的時候記得清除答案

代碼

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' || c > '9'
){if(c == '-')f = -1;c = getchar(); } while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar(); return x * f; } #define INF 1000000007 const int maxn = 200007; struct node { int v,w,next; } edge[maxn << 1]; int head[maxn],num; inline void add_edge(int
u,int v,int w) { edge[++ num].v = v;edge[num].w = w;edge[num].next = head[u];head[u] = num; } int n,k,root; bool vis[maxn]; int dis[maxn],son[maxn],f[maxn],deep[maxn],t[1000007],tot; void get_root(int x,int fa) { son[x] = 1;f[x] = 0; for(int i = head[x];i;i = edge[i].next) { int
v = edge[i].v; if(v == fa || vis[v]) continue; get_root(v,x); son[x] += son[v]; f[x] = std::max(f[x],son[v]); } f[x] = std::max(tot - son[x],f[x]); if(f[x] < f[root])root = x; } int ans = INF; void calc(int x,int fa) { if(dis[x] <= k) ans = std::min(ans,deep[x] + t[k - dis[x]]); else return; for(int i = head[x];i;i = edge[i].next) { int v = edge[i].v; if(vis[v] || edge[i].v == fa) continue; deep[v] = deep[x] + 1; dis[v] = dis[x] + edge[i].w; calc(v,x); } } void update(int x,int fa,bool ty) { if(dis[x] <= k) { if(ty)t[dis[x]] = std::min(t[dis[x]],deep[x]); else t[dis[x]] = n; } for(int i = head[x];i;i = edge[i].next) { int v = edge[i].v; if(v != fa && !vis[v]) update(v,x,ty); } } void sol(int x) { vis[x] = 1; t[0] = 0; for(int i = head[x];i;i = edge[i].next) { int v = edge[i].v; if(vis[v]) continue; deep[v] = 1;dis[v] = edge[i].w; calc(v,0);update(v,0,1); } for(int i = head[x];i;i = edge[i].next) if(!vis[edge[i].v]) update(edge[i].v,0,0); for(int i = head[x];i;i = edge[i].next) { if(!vis[edge[i].v]) { root = 0; tot = son[edge[i].v]; get_root(edge[i].v,0); sol(root); } } } int main() { n = read(),k = read(); for(int i = 1;i <= k;++ i) t[i] = n; for(int u,v,w,i = 1;i < n;++ i) { u = read() + 1,v = read() + 1,w = read(); add_edge(u,v,w); add_edge(v,u,w); } ans = tot = n;f[0] = n; get_root(1,0); sol(root); printf("%d\n",ans == n ? -1 : ans); return 0; }

bzoj2599: [IOI2011]Race