给出N(1 <= N <= 200000)个结点的树,求长度等于K(1 <= K <= 1000000)的路径的最小边数。

点分治,这道题目和POJ 2114很接近,2114是求是否存在长度为K的边,但是那个K比较大。但是这道题目的K比之小了10倍。

1. 用V[i]表示到当前树根root的路径长度为i 时的点(赋值为root结点即可),这样就可以用来判断两条到根的路径长度之和是否等于K:

结点a的root的距离为i,结点b到root的距离为j,处理完a之后会得到V[i] = root,那么在处理结点b的时候,如果V[K-j] = root,就说明某一个a和b的路径长度为K,此时,就可以更新最小边数了。

2. e[i]表示到当前树根root的路径长度为i 时的边的最小条数。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
#define N 200010
#define inf 0x3f3f3f3f
struct node {
int v, l;
node() {}
node(int _v, int _l): v(_v), l(_l) {};
};
vector<node> g[N];
int n, K, cur, root, size, ans;
int s[N], f[N], d[N], e[N]; //s子树的结点数,f求重心,d子结点到根的距离,e子结点到根的边数
int v[N*10], c[N*10];
bool done[N]; void getroot(int now, int fa) {
int u;
s[now] = 1, f[now] = 0;
for (int i=0; i<g[now].size(); i++)
if ((u = g[now][i].v) != fa && !done[u]) {
getroot(u, now);
s[now] += s[u];
f[now] = max(f[now], s[u]);
}
f[now] = max(f[now], size-s[now]);
if (f[now] < f[root]) root = now;
}
void dfs1(int now, int fa) {
if (d[now] > K) return ;
if (v[K-d[now]] == cur) ans = min(ans, c[K-d[now]]+e[now]);
int u;
for (int i=0; i<g[now].size(); i++)
if ((u = g[now][i].v) != fa && !done[u]) {
d[u] = d[now] + g[now][i].l;
e[u] = e[now] + 1;
dfs1(u, now);
}
}
void dfs2(int now, int fa) {
if (d[now] > K) return ;
if (v[d[now]] != cur) {
c[d[now]] = e[now];
v[d[now]] = cur;
} else c[d[now]] = min(c[d[now]], e[now]);
int u;
for (int i=0; i<g[now].size(); i++)
if ((u = g[now][i].v) != fa && !done[u])
dfs2(u, now);
}
void work(int now) {
v[0] = cur = now + 1;
int u;
for (int i=0; i<g[now].size(); i++)
if (!done[u = g[now][i].v]) {
d[u] = g[now][i].l;
e[u] = 1;
dfs1(u, now);
dfs2(u, now);
}
getroot(now, n); //更新s数组
done[now] = true;
for (int i=0; i<g[now].size(); i++)
if (!done[u = g[now][i].v]) {
f[n] = size = s[u];
getroot(u, root=n);
work(root);
}
}
int main() {
scanf("%d%d", &n, &K);
for (int i=0; i<=n; i++) g[i].clear(); for (int i=1, a, b, c; i<n; i++) {
scanf("%d%d%d", &a, &b, &c);
g[a].push_back(node(b, c));
g[b].push_back(node(a, c));
}
memset(done, false, sizeof(done)); ans = f[n] = size = n;
getroot(0, root=n);
work(root); printf("%d\n", ans < n ? ans : -1); return 0;
}

BZOJ 2599 [IOI2011]Race【Tree,点分治】的更多相关文章

  1. bzoj 2599 [IOI2011]Race (点分治)

    [题意] 问树中长为k的路径中包含边数最少的路径所包含的边数. [思路] 统计经过根的路径.假设当前枚举到根的第S个子树,若x属于S子树,则有: ans<-dep[x]+min{ dep[y] ...

  2. bzoj 2599: [IOI2011]Race【点分治】

    点分治,用一个mn[v]数组记录当前root下长为v的链的最小深度,每次新加一个儿子的时候都在原来儿子更新过的mn数组里更新ans(也就是查一下mn[m-dis[p]]+de[p]) 这里注意更新和初 ...

  3. BZOJ 2599: [IOI2011]Race( 点分治 )

    数据范围是N:20w, K100w. 点分治, 我们只需考虑经过当前树根的方案. K最大只有100w, 直接开个数组CNT[x]表示与当前树根距离为x的最少边数, 然后就可以对根的子树依次dfs并更新 ...

  4. bzoj 2599 [IOI2011]Race 点分

    [IOI2011]Race Time Limit: 70 Sec  Memory Limit: 128 MBSubmit: 4768  Solved: 1393[Submit][Status][Dis ...

  5. bzoj 2599: [IOI2011]Race (点分治 本地过了就是过了.jpg)

    题面:(复制别人的...) Description 给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. Input 第一行 两个整数 n, k第二..n行 每行三个整数 表示一条无向边的 ...

  6. 【刷题】BZOJ 2599 [IOI2011]Race

    Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k 第二 ...

  7. BZOJ 2599: [IOI2011]Race

    点分治,定权值,求另一关键字最小 不满足前缀加减性 可以按序遍历,用一数组$t[] 来维护路径为i的最小边数$ 再对于一个直系儿子对应的子树,先算距离求答案再更新$t数组,这样就不会重复$ #incl ...

  8. 2599: [IOI2011]Race

    2599: [IOI2011]Race 链接 分析 被memset卡... 点分治,对于重心,遍历子树,记录一个数组T[i],表示以重心为起点的长度为i的路径中最少的边数是多少.然后先遍历子树,更新答 ...

  9. 【BZOJ】2599: [IOI2011]Race 点分治

    [题意]给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000.注意点从0开始编号,无解输出-1. [算法]点分治 [题解] ...

随机推荐

  1. perl5 第六章 模式匹配

    第六章 模式匹配 by flamephoenix 一.简介二.匹配操作符三.模式中的特殊字符  1.字符+  2.字符 []和[^]  3.字符 *和?  4.转义字符  5.匹配任意字母或数字  6 ...

  2. 把一个数组向右循环移动k位要求时间复杂度为O(n)

    今晚做了下某公司的网络笔试题,好久没刷题了,现在渣得要死,里面有道程序设计题是 把一个数组向右循环移动k位要求时间复杂度为O(n) 给的方法定义为 public void solution(int a ...

  3. A计划(bfs)

    A计划 Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submissio ...

  4. Android Material Design-Creating Apps with Material Design(用 Material Design设计App)-(零)

    转载请注明出处:http://blog.csdn.net/bbld_/article/details/40400031 翻译自:http://developer.android.com/trainin ...

  5. 谁动了我的CurrentPrincipal?解释一下为什么CurrentPrincipal变了,并解决这个问题。

    在上一篇博客中我遇到了一个问题,并且导致了我无法继续进行授权和验证.经过查阅资料和解决另外一个问题的过程,我突然想通了为什么CurrentPrincipal变了.并且经过验证后的确是我所理解的那样.下 ...

  6. iOS开发之第三方登录微信-- 史上最全最新第三方登录微信方式实现

    项目地址 :    https://github.com/zhonggaorong/weixinLoginDemo 最新版本的微信登录实现步骤实现: 1.在进行微信OAuth2.0授权登录接入之前,在 ...

  7. c语言: 文件io, 拷贝文件(二进制)

    #include <stdio.h> #include <stdlib.h> #define TRAN_SZIE 1024 int copy_bin(char* from, c ...

  8. C函数调用与栈

    这篇blog试图说明这么一个问题,当一个c函数被调用时,一个栈帧(stack frame)是如何被建立,又如何被消除的.这些细节跟操作系统平台及编译器的实现有关,下面的描述是针对运行在Linux的gc ...

  9. django开发简易博客(四)

    上一节,我们讲述了怎么使用静态文件,并使用bootstrap对页面进行了美化,这一节我们将增强我们blog的功能,添加发表博客,删除博客的功能. 一.表单的使用 要实现添加blog的功能,就得使用表单 ...

  10. 关于android的坑

    坑1: 使用SQLiteOpenHelper的时候如果建立的表中存在不为空的字段,但是用ContentValues()的方式来插入数据的话恰好没有往这个字段里插入数据,那么执行后市没法往数据库里插入数 ...