题目描述

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

题解

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

ac代码

  1. # include <cstdio>
  2. # include <cstring>
  3. # include <algorithm>
  4. # include <ctype.h>
  5. # include <iostream>
  6. # include <cmath>
  7. # include <map>
  8. # include <vector>
  9. # include <queue>
  10. # define LL long long
  11. # define ms(a,b) memset(a,b,sizeof(a))
  12. # define ri (register int)
  13. # define inf (0x3f3f3f3f)/3
  14. # define pb push_back
  15. # define fi first
  16. # define se second
  17. # define pii pair<int,int>
  18. # define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
  19. using namespace std;
  20. inline int gi(){
  21. int w=0,x=0;char ch=0;
  22. while(!isdigit(ch)) w|=ch=='-',ch=getchar();
  23. while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  24. return w?-x:x;
  25. }
  26. # define N 1000005
  27. struct edge{
  28. int to,nt,w;
  29. }E[N<<1];
  30. int H[N],cnt,n,k,rt,sum,mx,sz[N],ans,mxs[N],d[N],dis[N],t[N];
  31. bool vis[N];
  32. void addedge(int u,int v,int w){
  33. E[++cnt]=(edge){v,H[u],w}; H[u]=cnt;
  34. }
  35. void get_root(int u,int fa){
  36. sz[u]=1; mxs[u]=-1;
  37. for (int e=H[u];e;e=E[e].nt){
  38. if (vis[E[e].to]||E[e].to==fa) continue;
  39. get_root(E[e].to,u);
  40. sz[u]+=sz[E[e].to];
  41. mxs[u]=max(mxs[u],sz[E[e].to]);
  42. }
  43. mxs[u]=max(sum-sz[u],mxs[u]);
  44. if (mxs[u]<mx) mx=mxs[u],rt=u;
  45. }
  46. void calc(int u,int fa){
  47. if (dis[u]<=k) ans=min(ans,d[u]+t[k-dis[u]]);//如果当前的距离是小于k的,那么就说明可能可以更新答案
  48. for (int e=H[u];e;e=E[e].nt){
  49. if (E[e].to==fa||vis[E[e].to]) continue;
  50. d[E[e].to]=d[u]+1;
  51. dis[E[e].to]=dis[u]+E[e].w;
  52. calc(E[e].to,u);
  53. }
  54. }
  55. void update(int u,int fa,bool fg){//更新边上的答案
  56. if (dis[u]<=k) {
  57. if (fg) t[dis[u]]=min(t[dis[u]],d[u]);//如果是访问过得,那么就直接更新
  58. else t[dis[u]]=inf;//如果没有访问过,那么就赋值成inf,防止重复
  59. }
  60. for (int e=H[u];e;e=E[e].nt){//继续更新边上的答案
  61. if (E[e].to==fa||vis[E[e].to]) continue;
  62. update(E[e].to,u,fg);
  63. }
  64. }
  65. void divide(int u){
  66. vis[u]=1; t[0]=0;
  67. for (int e=H[u];e;e=E[e].nt){
  68. if (vis[E[e].to]) continue;
  69. d[E[e].to]=1; dis[E[e].to]=E[e].w; calc(E[e].to,-1); update(E[e].to,-1,1);//计算全局的答案
  70. }
  71. for (int e=H[u];e;e=E[e].nt){//将所有没有访问过得答案还原,防止答案重复
  72. if (!vis[E[e].to]) update(E[e].to,-1,0);
  73. }
  74. for (int e=H[u];e;e=E[e].nt){//递归分治
  75. if (vis[E[e].to]) continue;
  76. mx=inf; sum=sz[E[e].to]; rt=0; get_root(E[e].to,-1); divide(rt);
  77. }
  78. }
  79. int main(){
  80. ms(t,inf); n=gi(),k=gi();
  81. for (int i=2;i<=n;i++){
  82. int u=gi(),v=gi(),w=gi();
  83. u++,v++;
  84. addedge(u,v,w); addedge(v,u,w);
  85. }
  86. sum=n; mx=inf; rt=-1; get_root(1,-1);
  87. ans=inf; divide(rt);
  88. printf("%d\n",(ans==inf)?(-1):(ans));
  89. return 0;
  90. }

[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. 网络七层模型及TCP、UDP,一次HTTP请求都发生了什么

    一.七层网络模型 http协议运行在应用层   二.TCP-UDP TCP.UDP协议的区别 一次Http 请求,这个过程都发生了什么 TCP 协议如何保证可靠传输 HTTP和HTTPS的区别 TCP ...

  2. mybatis事务管理机制详解

    1.mybatis事务的配置和使用 mybatis事务有两种使用方式: (a):使用JDBC的事务管理机制:即使用java.Sql.Connection对象完成对事务的提交,回滚和关闭操作. (b): ...

  3. sqlyog Can't connect to MySQL server on localhost (0)

    https://blog.csdn.net/l1336037686/article/details/78940223

  4. 大白跟着“菜鸟”学node——同名事件

    若存在两个同名事件,触发事件时,两个事件监听器的回调函数会被按次序先后调用. 实例来自菜鸟教程: var events=require('events'); var emitter=new event ...

  5. 关于controller的书写

    private Logger log = LoggerFactory.getLogger(ReportFormController.class); // 读取配置文件 ResourceBundle r ...

  6. python爬虫scrapy的LinkExtractor

    使用背景: 我们通常在爬去某个网站的时候都是爬去每个标签下的某些内容,往往一个网站的主页后面会包含很多物品或者信息的详细的内容,我们只提取某个大标签下的某些内容的话,会显的效率较低,大部分网站的都是按 ...

  7. Helm

    helm类似yum helm下载的是配置清单文件 核心术语: Chart:一个helm程序包: Repository:Charts仓库,https/http服务器: Release:特定的Chart部 ...

  8. ERP行业内幕看了这五个问题全懂了

    ERP系统是现代企业实现信息化管理的必经之路.但很多管理人员或已经在用ERP的人员,其实并不太懂ERP系统是什么意思,有哪些好处等,导致实际使用过程中经常大材小用,或者“英雄无用武之地”.所以,为了更 ...

  9. 猜数字游戏 在控制台运行--java详解!了;来玩

    import java.util.Scanner;//导入包 import java.util.Scanner; 注意格式 符号的使用 public class Demo{ //猜数字游戏 练习 pu ...

  10. time模块 转换关系图

    import time t = time.time() #获取目前时间 t_struck = time.localtime(t) #time.gmtime() utc时区 t_str = time.s ...