题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4326

题目大意:有一颗含有n个顶点的树,每两个点之间有一个边权,现在有m个运输计划,每个运输计划包含u和v,一个运输计划的代价为u到v的最短距离,现在可以使一条边的权值为0,求出使所以计划中代价最大值的最小值。

解题思路:最大值的最小值很明显需要二分答案,首先求出所以运输计划消耗的代价,然后二分答案mid,对于消耗的的代价大于mid的运输计划,假设有m条,我们只能使一条边的权值变为0,所以这条边必定是这m个运输计划的路径交,转化成一个求路径交的问题了,这里我们可以用树上差分来做,再开两个数组:tmp和prev。tmp用来记录点的出现次数(具体点说实际上记录的是点到其父亲的边的出现次数),prev记录每个点到其父亲的那条边权值。对于一条起点s,终点t的路径。我们这样处理:tmp[s]++,tmp[t]++,tmp[LCA(s,t)]-=2。最后要从所有叶结点把权值向上累加用一遍dfs就可以了。tmp[s]++,推到根后,根到s的tmp值均加了1,同理tmp[t]++,从根到t的tmp值也都加了1,而tmp[LCA(s,t)]-=2上推使得从根到LCA(s,t)的tmp值又变回原来的值,就能把多余的路径都减掉。对于多次操作,我只需要维护tmp的值,最后一次性上推即可。如果tmp[i]等于路径的个数,即代表i到其父亲的那条边是所有路径的交。

代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. typedef long long ll;
  6. const int maxn=;
  7. int n,m,dist[maxn],tot,depth[maxn],head[maxn],fa[maxn][],tmp[maxn],prev[maxn];
  8. struct Edge{
  9. int v,next,w;
  10. }edge[maxn*];
  11. void add(int u,int v,int w){
  12. edge[tot].v=v;
  13. edge[tot].w=w;
  14. edge[tot].next=head[u];
  15. head[u]=tot++;
  16. }
  17. struct Query{
  18. int u,v,dis,lca;
  19. }q[maxn];
  20. void dfs(int u,int pre){
  21. depth[u]=depth[pre]+;
  22. fa[u][]=pre;
  23. for(int i=;i<=;i++)
  24. fa[u][i]=fa[fa[u][i-]][i-];
  25. for(int i=head[u];i!=-;i=edge[i].next){
  26. int v=edge[i].v;
  27. if(v==pre){
  28. prev[u]=edge[i].w;
  29. continue;
  30. }
  31. dist[v]=dist[u]+edge[i].w;
  32. if(v!=pre) dfs(v,u);
  33. }
  34. }
  35. int LCA(int u,int v){
  36. if(depth[u]<depth[v]) swap(u,v);
  37. for(int i=;i>=;i--){
  38. if(depth[u]-(<<i)>=depth[v]) u=fa[u][i];
  39. }
  40. if(u==v) return u;
  41. for(int i=;i>=;i--){
  42. if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
  43. }
  44. return fa[u][];
  45. }
  46. void dfs1(int u,int pre){
  47. for(int i=head[u];i!=-;i=edge[i].next){
  48. int v=edge[i].v;
  49. if(v==pre) continue;
  50. dfs1(v,u);
  51. tmp[u]+=tmp[v];
  52. }
  53. }
  54. bool check(int x){
  55. memset(tmp,,sizeof(tmp));
  56. int cnt=;
  57. int Maxx=;
  58. for(int i=;i<=m;i++){
  59. if(q[i].dis>x){
  60. tmp[q[i].u]++;
  61. tmp[q[i].v]++;
  62. tmp[q[i].lca]-=;
  63. Maxx=max(Maxx,q[i].dis);
  64. cnt++;
  65. }
  66. }
  67. if(cnt==)return true;
  68. dfs1(,);
  69. for(int i=;i<=n;i++){
  70. if(tmp[i]==cnt&&Maxx-prev[i]<=x) return true;
  71. }
  72. return false;
  73. }
  74. int main(){
  75. memset(head,-,sizeof(head));
  76. scanf("%d%d",&n,&m);
  77. for(int i=;i<n;i++){
  78. int u,v,w;
  79. scanf("%d%d%d",&u,&v,&w);
  80. add(u,v,w); add(v,u,w);
  81. }
  82. depth[]=-;
  83. dfs(,);
  84. for(int i=;i<=m;i++){
  85. scanf("%d%d",&q[i].u,&q[i].v);
  86. q[i].lca=LCA(q[i].u,q[i].v);
  87. q[i].dis=dist[q[i].u]+dist[q[i].v]-*dist[q[i].lca];
  88. // cout<<q[i].dis<<endl;
  89. // cout<<dist[q[i].u]<<" "<<dist[q[i].v]<<" "<<dist[lca(q[i].u,q[i].v)]<<endl;
  90. }
  91. int l=,r=1e9;
  92. int ans;
  93. while(l<=r){
  94. int mid=(l+r)/;
  95. if(check(mid)){
  96. ans=mid;
  97. r=mid-;
  98. }else l=mid+;
  99. }
  100. printf("%d\n",ans);
  101. return ;
  102. }

bzoj4326: NOIP2015 运输计划(二分+LCA+树上差分)的更多相关文章

  1. BZOJ 4326: NOIP2015 运输计划(二分,树上差分)

    Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1945  Solved: 1243[Submit][Status][Discuss] Descript ...

  2. P2680 运输计划[二分+LCA+树上差分]

    题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n−1 条航道连通了 LL 国的所有星球. 小 ...

  3. [luogu]P2680 运输计划[二分答案][树上差分]

    [luogu]P2680 [NOIP2015]运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n ...

  4. 洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)

    [题目链接] [思路]: 根据题意可以明显看出,当所有任务都完成时的时间是最终的结果,也就是说本题要求,求出最小的最大值. 那这样的话就暗示了将答案二分,进行check. [check方法]: 如果说 ...

  5. loj2425 「NOIP2015」运输计划[二分答案+树上差分]

    看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\text{mid}$,然后尝试检验.````` 检验是否存在这样一个边置为0后,全部链长$\le\text{mid}$,其最终目标就是.要让所 ...

  6. luogu P2680 运输计划 (二分答案+树上差分)

    题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间 ...

  7. LOJ2425 NOIP2015 运输计划 【二分+LCA+树上差分】*

    LOJ2425 NOIP2015 运输计划 LINK 题意:给你一颗树,可以将任意一条边的权值变成0,然后求m条路径的长度的最小值 思路: 先二分最后的距离ans,然后我们把路程大于ans的所有路径拿 ...

  8. BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1930  Solved: 1231[Submit][Statu ...

  9. [NOIP2015]运输计划 线段树or差分二分

    目录 [NOIP2015]运输计划 链接 思路1 暴力数据结构 思路2 二分树上差分 总的 代码1 代码2 [NOIP2015]运输计划 链接 luogu 好久没写博客了,水一篇波. 思路1 暴力数据 ...

  10. NOIP2015 运输计划 - 二分 + 树链剖分 / (倍增 + 差分)

    BZOJ CodeVS Uoj 题目大意: 给一个n个点的边带权树,给定m条链,你可以选择树中的任意一条边,将它置为0,使得最长的链长最短. 题目分析: 最小化最大值,二分. 二分最短长度mid,将图 ...

随机推荐

  1. 《Effective Java》读书笔记 - 10.并发

    Chapter 10 Concurrency Item 66: Synchronize access to shared mutable data synchronized这个关键字不仅保证了同步,还 ...

  2. vue递归组件的实现

    本文链接:https://blog.csdn.net/weixin_43756060/article/details/87786344vue递归实现图片上的多级菜单 父级组件结构 <templa ...

  3. 使用指定MTU到特定IP

    ping指令使用指定MTU到特定IP 命令如下 45.58.185.18 这里MTU为1300

  4. [python] Pythonic语法笔记

    Pythonic语法笔记 __new__ 在类实例化之前执行的,也就是在init之前执行,可以为这个类写操作.接受的参数不是self而是cls.只有在new方法里返回类才会执行init操作,需要返回父 ...

  5. java dwg转svg

    package com.example.demo.dxf2svg; import com.aspose.cad.InterpolationMode; import com.aspose.cad.Smo ...

  6. Collector解读以及自定义

    一.Collector接口解读: Collector接口解读: public interface Collector<T, A, R> { Supplier<A> suppli ...

  7. 测开之路一百四十三:ORM框架之SQLAlchemy模型及表创建

    基于前一篇内容,可以使用模型的结构 目录结构 main,入口层 from flask import Flaskfrom flask_sqlalchemy import SQLAlchemy app = ...

  8. 程序的内存分布 - 以 Linux 为例,基于 C 语言分析

    这里以 Linux 为例,用 C 语言进行演示. 内存模型 - 内存空间名称 内容 读写操作 分配时机 高地址 kernel 内核空间 命令行参数.环境变量等 不可读写 程序运行时 - stack 栈 ...

  9. Java多线程学习——synchronized锁机制

    Java在多线程中使用同步锁机制时,一定要注意锁对对象,下面的例子就是没锁对对象(每个线程使用一个被锁住的对象时,得先看该对象的被锁住部分是否有人在使用) 例子:两个人操作同一个银行账户,丈夫在ATM ...

  10. paramiko远程连接linux服务器进行上传下载文件

    花了不少时间来研究paramiko中sftpclient的文件传输,一顿操作猛如虎,最后就一直卡在了路径报错问题,疯狂查阅资料借鉴大佬们的心得,还是搞不好,睡了个午觉醒来,仔细一看原来是指定路径的文件 ...