zoukankan      html  css  js  c++  java
  • BZOJ2599: [IOI2011]Race

    Time Limit: 70 Sec Memory Limit: 128 MB
    Submit: 4711 Solved: 1382
    [Submit][Status][Discuss]

    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

    HINT

    2018.1.3新加数据一组,未重测

    Source

    题解

    点分治,每一块,维护(dis[x])表示重心到x距离,全局维护(f[x])表示长度为(x)的路径最小点数。用(dis)更新(f[x])的时候,只需要对于每一棵子树,统计完(dis)后更新f即可,这样保证两个点的路径一定被统计一次。
    注意点编号从(0)开始,且边权有(0),因此初值(f[0]=0,f[x]=INF,x eq0)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <cmath>
    inline int max(int a, int b){return a > b ? a : b;}
    inline int min(int a, int b){return a < b ? a : b;}
    inline void swap(int &x, int &y){int  tmp = x;x = y;y = tmp;}
    inline void read(int &x)
    {
        x = 0;char ch = getchar(), c = ch;
        while(ch < '0' || ch > '9') c = ch, ch = getchar();
        while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
        if(c == '-') x = -x;
    }
    const int INF = 0x3f3f3f3f;
    const int MAXN = 200000 + 10;
    const int MAXK = 1000000 + 10;
    
    struct Edge
    {
    	int u, v, w, nxt;
    	Edge(int _u, int _v, int _w, int _nxt){u = _u, v = _v, w = _w, nxt = _nxt;}
    	Edge(){}
    }edge[MAXN << 1];
    int head[MAXN], cnt, root, vis[MAXN], sum, dp[MAXN], size[MAXN], f[MAXK], dis[MAXN], num[MAXN], ans, n, k;
    inline void insert(int a, int b, int c){edge[++ cnt] = Edge(a, b, c, head[a]), head[a] = cnt;}
    void dfs_dis(int x, int pre)
    {
    	if(dis[x] <= k) ans = min(ans, num[x] + f[k - dis[x]]);
    	for(int pos = head[x];pos;pos = edge[pos].nxt) 
    	{
    		int v = edge[pos].v;
    		if(vis[v] || v == pre) continue;
    		dis[v] = edge[pos].w + dis[x], num[v] = num[x] + 1, dfs_dis(v, x);
    	}
    }
    int dfs_f(int x, int flag, int pre)
    {
    	if(dis[x] <= k) 
    	{
    		if(flag) f[dis[x]] = min(f[dis[x]], num[x]);
    		else f[dis[x]] = dis[x] == 0 ? 0 : INF;
    	}
    	for(int pos = head[x];pos;pos = edge[pos].nxt)
    	{
    		int v = edge[pos].v;
    		if(vis[v] || v == pre) continue;
    		dfs_f(v, flag, x);
    	}
    }
    void dfs_dp(int x, int pre)
    {
    	size[x] = 1, dp[x] = 0;
    	for(int pos = head[x];pos;pos = edge[pos].nxt)
    	{
    		int v = edge[pos].v;
    		if(vis[v] || v == pre) continue;
    		dfs_dp(v, x), size[x] += size[v], dp[x] = max(dp[x], size[v]);
    	}
    	dp[x] = max(dp[x], sum - size[x]);
    	if(dp[x] < dp[root]) root = x;
    }
    void solve(int x)
    {
    	root = 0;
    	dfs_dp(x, -1), x = root;
    	vis[x] = 1; 
    	for(int pos = head[x];pos;pos = edge[pos].nxt)
    	{
    		int v = edge[pos].v;
    		if(vis[v]) continue;
    		num[v] = 1, dis[v] = edge[pos].w;
    		dfs_dis(v, -1), dfs_f(v, 1, -1);
    	}
    	for(int pos = head[x];pos;pos = edge[pos].nxt)
    	{
    		int v = edge[pos].v;
    		if(vis[v]) continue;
    		dfs_f(v, 0, -1);
    	}
    	for(int pos = head[x];pos;pos = edge[pos].nxt)
    	{
    		int v = edge[pos].v;
    		if(vis[v]) continue;
    		sum = size[v];
    		solve(v);
    	}
    }
    int main()
    {
    	memset(f, 0x3f, sizeof(f)), f[0] = 0, ans = INF;
    	read(n), read(k);
    	for(int i = 1;i < n;++ i)
    	{
    		int tmp1, tmp2, tmp3;
    		read(tmp1), read(tmp2), read(tmp3);
    		++ tmp1, ++ tmp2;
    		insert(tmp1, tmp2, tmp3), insert(tmp2, tmp1, tmp3);
    	}
    	sum = n, dp[0] = INF, solve(1);
    	if(ans != INF) printf("%d", ans);
    	else printf("-1");
     	return 0;
    }
    
  • 相关阅读:
    python入门_老男孩_文件操作
    python入门_老男孩_列表和字典循环删除的正确方法
    python入门_老男孩_集合_元祖
    linux入门_韩顺平_复习版_文件目录类
    python-re模块
    sorted()函数
    偏函数+高阶函数
    生成器
    闭包
    匿名函数
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8777151.html
Copyright © 2011-2022 走看看