bzoj2599 [IOI2011]Race

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

posted @ 2018-06-01 20:50  沛霖  阅读(119)  评论(0编辑  收藏  举报