题目描述

给一棵树,每条边有权。求一条简单路径,权值和等于 K,且边的数量最小。

题解

比较明显需要用到点分治,我们定义\(d\)数组表示当前节点到根节点\(rt\)之间有多少个节点,也可以表示有多少条边,然后我们在定义\(dis\)表示当前节点到根节点\(rt\)的距离,那么我们就可以得到\(ans=min(ans,d[u]+t[k-dis[u]])\),这个方程还是比较容易的。
但是这道题目不满足状态可减性,说的明白一点就是答案和答案之间无法相减,那么点分治的容斥原理处理就可以变成将原来没有访问过得节点的答案都变成\(inf\),这样我们算的时候就不会把这些重复部分算多次。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x3f3f3f3f)/3
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 1000005
struct edge{
    int to,nt,w;
}E[N<<1];
int H[N],cnt,n,k,rt,sum,mx,sz[N],ans,mxs[N],d[N],dis[N],t[N];
bool vis[N];
void addedge(int u,int v,int w){
    E[++cnt]=(edge){v,H[u],w}; H[u]=cnt;
}
void get_root(int u,int fa){
    sz[u]=1; mxs[u]=-1;
    for (int e=H[u];e;e=E[e].nt){
        if (vis[E[e].to]||E[e].to==fa) continue;
        get_root(E[e].to,u);
        sz[u]+=sz[E[e].to];
        mxs[u]=max(mxs[u],sz[E[e].to]);
    }
    mxs[u]=max(sum-sz[u],mxs[u]);
    if (mxs[u]<mx) mx=mxs[u],rt=u;
}
void calc(int u,int fa){
    if (dis[u]<=k) ans=min(ans,d[u]+t[k-dis[u]]);//如果当前的距离是小于k的,那么就说明可能可以更新答案
    for (int e=H[u];e;e=E[e].nt){
        if (E[e].to==fa||vis[E[e].to]) continue;
        d[E[e].to]=d[u]+1;
        dis[E[e].to]=dis[u]+E[e].w;
        calc(E[e].to,u);
    }
}
void update(int u,int fa,bool fg){//更新边上的答案
    if (dis[u]<=k) {
        if (fg) t[dis[u]]=min(t[dis[u]],d[u]);//如果是访问过得,那么就直接更新
        else t[dis[u]]=inf;//如果没有访问过,那么就赋值成inf,防止重复
    }
    for (int e=H[u];e;e=E[e].nt){//继续更新边上的答案
        if (E[e].to==fa||vis[E[e].to]) continue;
        update(E[e].to,u,fg);
    }
}
void divide(int u){
    vis[u]=1; t[0]=0;
    for (int e=H[u];e;e=E[e].nt){
        if (vis[E[e].to]) continue;
        d[E[e].to]=1; dis[E[e].to]=E[e].w; calc(E[e].to,-1); update(E[e].to,-1,1);//计算全局的答案
    }
    for (int e=H[u];e;e=E[e].nt){//将所有没有访问过得答案还原,防止答案重复
        if (!vis[E[e].to]) update(E[e].to,-1,0);
    }
    for (int e=H[u];e;e=E[e].nt){//递归分治
        if (vis[E[e].to]) continue;
        mx=inf; sum=sz[E[e].to]; rt=0; get_root(E[e].to,-1); divide(rt);
    }
}
int main(){
    ms(t,inf); n=gi(),k=gi();
    for (int i=2;i<=n;i++){
        int u=gi(),v=gi(),w=gi();
        u++,v++;
        addedge(u,v,w); addedge(v,u,w);
    }
    sum=n; mx=inf; rt=-1; get_root(1,-1);
    ans=inf; divide(rt);
    printf("%d\n",(ans==inf)?(-1):(ans));
    return 0;
}

[luogu4149][bzoj2599][IOI2011]Race【点分治】的更多相关文章

  1. [bzoj2599][IOI2011]Race——点分治

    Brief Description 给定一棵带权树,你需要找到一个点对,他们之间的距离为k,且路径中间的边的个数最少. Algorithm Analyse 我们考虑点分治. 对于子树,我们递归处理,所 ...

  2. BZOJ2599:[IOI2011]Race(点分治)

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

  3. 【BZOJ-2599】Race 点分治

    2599: [IOI2011]Race Time Limit: 70 Sec  Memory Limit: 128 MBSubmit: 2590  Solved: 769[Submit][Status ...

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

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

  5. [IOI2011]Race 点分治

    [IOI2011]Race LG传送门 点分治板子题. 直接点分治统计,统计的时候开个桶维护下就好了. 注(tiao)意(le)细(hen)节(jiu). #include<cstdio> ...

  6. bzoj2599/luogu4149 [IOI2011]Race (点分治)

    点分治.WA了一万年. 重点就是统计答案的方法 做法一(洛谷AC bzojWA 自测WA): 做点x时记到x距离为k的边数最小值为dis[k],然后对每一对有值的dis[i]和dis[K-i],给an ...

  7. bzoj2599: [IOI2011]Race(点分治)

    写了四五道点分治的题目了,算是比较理解点分治是什么东西了吧= = 点分治主要用来解决点对之间的问题的,比如距离为不大于K的点有多少对. 这道题要求距离等于K的点对中连接两点的最小边数. 那么其实道理是 ...

  8. 2019.01.09 bzoj2599: [IOI2011]Race(点分治)

    传送门 题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. 思路: 考虑点分治如何合并. 我们利用树形dpdpdp求树的直径的方法,边dfsdfsdfs子树边统计答案即可. 代码: ...

  9. BZOJ2599 [IOI2011]Race 【点分治】

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

随机推荐

  1. 学习mongoDB的一些感受(转自:http://blog.csdn.net/liusong0605/article/details/11581019)

    曾经使用过mongoDB来保存文件,最一开始,只是想总结一下在开发中如何实现文件与mongoDB之间的交互.在此之前,并没有系统的了解过mongoDB,虽然知道我们用它来存储文件这些非结构化数据,但是 ...

  2. mysql之整合ssm多数据源配置

    一,基于SSM框架的多数据源配置 1.创建DynamicDataSourceHolder用于持有当前线程中使用的数据源标识 public class DynamicDataSourceHolder { ...

  3. HDU 2003 求绝对值

    http://acm.hdu.edu.cn/showproblem.php?pid=2003 Problem Description 求实数的绝对值.   Input 输入数据有多组,每组占一行,每行 ...

  4. 架构 规则引擎 quartz

    通向架构师的道路(第五天)之tomcat集群-群猫乱舞-云栖社区-阿里云https://yq.aliyun.com/articles/259343 商业规则引擎和开源规则引擎的测试对比 - qq_39 ...

  5. HTTP之referrer

    我们知道,在页面引入图片.JS 等资源,或者从一个页面跳到另一个页面,都会产生新的 HTTP 请求,浏览器一般都会给这些请求头加上表示来源的 Referrer 字段.Referrer 在分析用户来源时 ...

  6. 优化CSS重排重绘与浏览器性能

    关于CSS重排和重绘的概念,最近看到不少这方面的文章,觉得挺有用,在制作中考虑浏览器的性能,减少重排能够节省浏览器对其子元素及父类元素的重新渲染:避免过分的重绘也能节省浏览器性能:优化动画,使用3D启 ...

  7. hadoop第一个例子

    Java.io.URL 1.编写java程序 package com.company; import java.io.IOException; import java.io.InputStream; ...

  8. windows10企业版2016长期服务版激活

    win10 2016 长期服务版的ISO文件中本身就带有KMS激活KEY,不用输入任何KEY,连接网络进入CMD,只要输入:slmgr /skms kms.digiboy.irslmgr /ato这两 ...

  9. python之路--MySQL 库,表的详细操作

    一 库操作 数据库命名规则 可以由数字,字母,下划线,@, #, $ 区分大小写 唯一性 不能使用关键字如 create  select 不能单独使用数字 最长128位 # 这些是对上次的补充. 二 ...

  10. Ansible入门与实践

    一.ansible介绍 Ansible是一个简单的自动化运维管理工具,基于Python语言实现,由Paramiko和PyYAML两个关键模块构建,可用于自动化部署应用.配置.编排task(持续交付.无 ...