[IOI2011]Race
Time Limit: 70 Sec Memory Limit: 128 MB
Description
给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000
Input
第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
一个整数 表示最小边数量 如果不存在这样的路径 输出-1
Sample Input
4 3
0 1 1
1 2 2
1 3 4
Sample Output
2
淀粉质这个东西。。。。就是复杂度科学的递归。。。
就是注意清空的时候原路返回吧。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5, INF = 0x3f3f3f3f;
struct lpl{
int to, dis;
}lin;
vector<lpl> point[maxn];
int n, k, sum, ans, root;
int size[maxn], d[maxn], ds[maxn], f[maxn], lpd[1000006];
bool vis[maxn];
inline void putit()
{
int x, y;
scanf("%d%d", &n, &k); sum = ans = f[0] = n;
for(int i = 1; i < n; ++i){
scanf("%d%d%d", &x, &y, &lin.dis); x++, y++;
lin.to = y; point[x].push_back(lin);
lin.to = x; point[y].push_back(lin);
}
for(int i = 1; i <= k; ++i) lpd[i] = n;
}
void getroot(int t, int fa)
{
size[t] = 1; f[t] = 0;
for(int i = point[t].size() - 1; i >= 0; --i){
int now = point[t][i].to;
if(now == fa || vis[now]) continue;
getroot(now, t);
size[t] += size[now];
f[t] = max(f[t], size[now]);
}
f[t] = max(f[t], sum - size[t]);
if(f[t] < f[root]) root = t;
}
void add(int t, int fa, bool flag)
{
if(ds[t] <= k){
if(flag) lpd[ds[t]] = min(lpd[ds[t]], d[t]);
else lpd[ds[t]] = INF;
}
for(int i = point[t].size() - 1; i >= 0; --i){
int now = point[t][i].to;
if(now == fa || vis[now]) continue;
add(now, t, flag);
}
}
void calc(int t, int fa)
{
if(ds[t] <= k) ans = min(ans, d[t] + lpd[k - ds[t]]);
for(int i = point[t].size() - 1; i >= 0; --i){
int now = point[t][i].to;
if(now == fa || vis[now]) continue;
d[now] = d[t] + 1; ds[now] = ds[t] + point[t][i].dis;
calc(now, t);
}
}
void workk(int t)
{
vis[t] = true; lpd[0] = 0; d[t] = 0;
for(int i = point[t].size() - 1; i >= 0; --i){
int now = point[t][i].to;
if(vis[now]) continue;
d[now] = 1; ds[now] = point[t][i].dis;
calc(now, 0); add(now, 0, 1);
}
for(int i = point[t].size() - 1; i >= 0; --i){
int now = point[t][i].to;
if(vis[now]) continue;
add(now, 0, 0);
}
for(int i = point[t].size() - 1; i >= 0; --i){
int now = point[t][i].to;
if(vis[now]) continue;
root = 0; sum = size[now]; getroot(now, 0); workk(root);
}
}
inline void print()
{
if(ans == n) printf("-1");
else cout << ans;
}
int main()
{
putit();
getroot(1, 0);
workk(root);
print();
return 0;
}