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;
}