• 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;
    }
    
    
    心如花木,向阳而生。
  • 相关阅读:
    动态归划之不同路径走法之和
    【转】在ADO.NET中使用参数化SQL语句的大同小异
    asp.net C#如何实现验证码不区分大小写
    用C# + SqlServer2005 实现的treeview动态树形菜单
    捕捉用户的输入,用回车提交
    【转载】在一个aspx或ashx页面里进行多次ajax调用
    【转】在ashx页面中context.Session["xxx"]获取不到值的解决办法
    【转载】【很不错的文章,值得一看】实现小数据量和海量数据的通用分页显示存储过程
    【原创】纯javascript实现银行卡号的Luhn验证或校验算法
    Sql
  • 原文地址:https://www.cnblogs.com/LLppdd/p/9123388.html
Copyright © 2020-2023  润新知