题目链接: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到其父亲的那条边是所有路径的交。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=;
int n,m,dist[maxn],tot,depth[maxn],head[maxn],fa[maxn][],tmp[maxn],prev[maxn];
struct Edge{
int v,next,w;
}edge[maxn*];
void add(int u,int v,int w){
edge[tot].v=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot++;
}
struct Query{
int u,v,dis,lca;
}q[maxn];
void dfs(int u,int pre){
depth[u]=depth[pre]+;
fa[u][]=pre;
for(int i=;i<=;i++)
fa[u][i]=fa[fa[u][i-]][i-];
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
if(v==pre){
prev[u]=edge[i].w;
continue;
}
dist[v]=dist[u]+edge[i].w;
if(v!=pre) dfs(v,u);
}
}
int LCA(int u,int v){
if(depth[u]<depth[v]) swap(u,v);
for(int i=;i>=;i--){
if(depth[u]-(<<i)>=depth[v]) u=fa[u][i];
}
if(u==v) return u;
for(int i=;i>=;i--){
if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
}
return fa[u][];
}
void dfs1(int u,int pre){
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
if(v==pre) continue;
dfs1(v,u);
tmp[u]+=tmp[v];
}
}
bool check(int x){
memset(tmp,,sizeof(tmp));
int cnt=;
int Maxx=;
for(int i=;i<=m;i++){
if(q[i].dis>x){
tmp[q[i].u]++;
tmp[q[i].v]++;
tmp[q[i].lca]-=;
Maxx=max(Maxx,q[i].dis);
cnt++;
}
}
if(cnt==)return true;
dfs1(,);
for(int i=;i<=n;i++){
if(tmp[i]==cnt&&Maxx-prev[i]<=x) return true;
}
return false;
}
int main(){
memset(head,-,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=;i<n;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
}
depth[]=-;
dfs(,);
for(int i=;i<=m;i++){
scanf("%d%d",&q[i].u,&q[i].v);
q[i].lca=LCA(q[i].u,q[i].v);
q[i].dis=dist[q[i].u]+dist[q[i].v]-*dist[q[i].lca];
// cout<<q[i].dis<<endl;
// cout<<dist[q[i].u]<<" "<<dist[q[i].v]<<" "<<dist[lca(q[i].u,q[i].v)]<<endl;
}
int l=,r=1e9;
int ans;
while(l<=r){
int mid=(l+r)/;
if(check(mid)){
ans=mid;
r=mid-;
}else l=mid+;
}
printf("%d\n",ans);
return ;
}

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. eclipse连接Mysql和测试

    一.前期准备: 1.eclipse 2.Mysql workbench 3.jdbc 下载地址:https://www.mysql.com/products/connector/ 点击JDBC Dri ...

  2. Fatal error: Class 'think\db' not found

    在model层写了一个查询语句结果报错 Fatal error: Class 'think\db' not found   $list= Db::table('m_my_reserve_assess' ...

  3. 面试题:String类通用构造,拷贝构造,析构,赋值函数实现

    已知 String 类定义如下: class String { public: //通用构造函数 String(const char* str = NULL); //拷贝构造函数 String(con ...

  4. Python 2 和 3 的区别及兼容技巧

    目录 目录 前言 Python 2 or 3 ? 不同与兼容 统一不等于语法 统一整数类型 统一整数除法 统一缩进语法 统一类定义 统一字符编码类型 统一导入模块的路径搜索方式 修正列表推导式的变量作 ...

  5. robotframework(rf)中对时间操作的datetime库常用关键字

    1.对固定日期进行操作,增加或减去单位时间或者时间段 2.对两个时间段进行操作 3.对时间格式转化,获取时间戳. 4.从完整时间中取指定年月日等 5.对时间类型进行格式化 6.获取当前时间或者指定时区 ...

  6. Java ——集合框架 list lambda set map 遍历方法 数据结构

    本节重点思维导图 集合框架 有序无序:元素放入的顺序与取出的顺序是否一致,一致即为有序,不一致即无序. List:允许重复.有序 ArrayList:长度可变的数组,遍历速度快 LinkedList: ...

  7. 【Linux开发】Linux及Arm-Linux程序开发笔记(零基础入门篇)

    Linux及Arm-Linux程序开发笔记(零基础入门篇) 作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/beer ...

  8. 【Linux开发】arm-linux-gnueabihf-gcc下载

    原文地址:http://www.veryarm.com/arm-linux-gnueabihf-gcc veryarm是个不错的网站,里面介绍了很多相关的基础知识. arm-linux-gnueabi ...

  9. Linux 自学shell

    1.多个命令用";"分号分割 还可以使用alias 给命令取别名 alias foo='cd /usr ; ls; cd -'2.使用管道线"|" 一个命令的标 ...

  10. unittest中的断言方法

    方法        用途 assertEqual(a,b)      a=b assertNotEqual(a,b)    a!=b assertTrue(x)     x为True assertFa ...