zoukankan      html  css  js  c++  java
  • 「Luogu P4149」「IOI2011」Race

    Description

    给一棵 (n) 个点的树,每条边有权。求一条简单路径,权值和等于 (k),且边的数量最小。

    Hint

    • (1le nle 2 imes 10^5)
    • (1le k, ext{边权}le 10^6)

    Solution

    还行的一道点分治题。

    (k) 的范围不是很大,所以开一个大小为 (10^6) 的桶,( ext{rec}_i) 表示权值和为 (i) 的路径的最小边数。

    更具体地,假如当前重心(根)结点的所有子树的根分别为:(x_1,x_2,cdots,x_k),而现在处理好了 (x_1,x_2,cdots,x_{k-1}) 这几颗子树之间产生的答案,那么 ( ext{rec}) 就保存了 (x_1,x_2,cdots,x_{k-1}) 这几颗子树中所有结点到根路径的信息。

    对于子树 (x_k) 中某一条路径,长度和权值分别为 ((L, V)),那么这样更新答案:( ext{ans}leftarrow min( ext{ans}, ext{rec}_{k-V}+L))

    在处理完一颗子树之后,对于该子树中所有的路径,对 (rec) 这样更新:( ext{rec}_V leftarrow min( ext{rec}_V, L))

    于是……这道题就切掉了 QwQ!

    • 时间复杂度:(O(nlog n))
    • 空间复杂度:(O(n+k))

    Code

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : Luogu P4149 IOI2011 Race
     */
    #include <cstdio>
    #include <cstring>
    #include <utility>
    #include <vector>
    
    using namespace std;
    const int N = 2e5 + 5;
    const int K = 1e6 + 5;
    
    int n, k, ans;
    struct edge { int to, val; };
    vector<edge> G[N];
    
    int root;
    int maxp[N], size[N];
    bool centr[N];
    int getSize(int x, int f) {
    	size[x] = 1;
    	for (auto y : G[x])
    		if (y.to != f && !centr[y.to])
    			size[x] += getSize(y.to, x);
    	return size[x];
    }
    void getCentr(int x, int f, int t) {
    	maxp[x] = 0;
    	for (auto y : G[x]) {
    		if (y.to == f || centr[y.to]) continue;
    		getCentr(y.to, x, t);
    		maxp[x] = max(maxp[x], size[y.to]);
    	}
    	maxp[x] = max(maxp[x], t - size[x]);
    	if (maxp[x] < maxp[root]) root = x;
    }
    
    int tot;
    pair<int, int> path[N];
    vector<pair<int, int> > all;
    int rec[K];
    void getPaths(int x, int f, int l, int v) {
    	if (v > k) return;
    	path[++tot] = {l, v};
    	for (auto y : G[x])
    		if (y.to != f && !centr[y.to])
    			getPaths(y.to, x, l + 1, v + y.val);
    }
    
    void solve(int x) {
    	getSize(x, 0);
    	maxp[root = 0] = N;
    	getCentr(x, 0, size[x]);
    	int s = root;
    	centr[s] = true;
    	
    	for (auto y : G[s])
    		if (!centr[y.to]) solve(y.to);
    	
    	rec[0] = 0;
    	for (auto y : G[s]) {
    		if (centr[y.to]) continue;
    		tot = 0, getPaths(y.to, x, 1, y.val);
    		for (register int i = 1; i <= tot; i++)
    			ans = min(ans, rec[k - path[i].second] + path[i].first);
    		for (register int i = 1; i <= tot; i++) {
    			all.push_back(path[i]);
    			rec[path[i].second] = min(path[i].first, rec[path[i].second]);
    		}
    	}
    	
    	for (auto i : all)
    		rec[i.second] = 0x3f3f3f3f;
    	all.clear();
    	centr[s] = false;
    }
    
    signed main() {
    	scanf("%d%d", &n, &k);
    	for (register int i = 1; i < n; i++) {
    		int s, t, v;
    		scanf("%d%d%d", &s, &t, &v);
    		s++, t++;
    		G[s].push_back(edge{t, v});
    		G[t].push_back(edge{s, v});
    	}
    	
    	memset(rec, 0x3f, sizeof rec);
    	ans = N, solve(1);
    	printf("%d
    ", ans == N ? -1 : ans);
    	return 0;
    }
    
  • 相关阅读:
    SQL序列键
    SQL日期跟时间值序列
    springboot日志配置
    weblogic10补丁升级与卸载
    idea使用svn报错
    mybatis插入数据并返回主键(oracle)
    UTF-8格式txt文件读取字节前三位问题
    https连接器
    git将本地项目上传码云
    aop的使用
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12853760.html
Copyright © 2011-2022 走看看