[IOI2011]Race
Posted alecli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[IOI2011]Race相关的知识,希望对你有一定的参考价值。
题意
思考
简要题意:给一棵树,每条边有权。求一条简单路径,权值和等于 (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的主要内容,如果未能解决你的问题,请参考以下文章