bzoj4326: NOIP2015 运输计划(二分+LCA+树上差分)
题目链接: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+树上差分)的更多相关文章
- BZOJ 4326: NOIP2015 运输计划(二分,树上差分)
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1945 Solved: 1243[Submit][Status][Discuss] Descript ...
- P2680 运输计划[二分+LCA+树上差分]
题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n−1 条航道连通了 LL 国的所有星球. 小 ...
- [luogu]P2680 运输计划[二分答案][树上差分]
[luogu]P2680 [NOIP2015]运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n ...
- 洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)
[题目链接] [思路]: 根据题意可以明显看出,当所有任务都完成时的时间是最终的结果,也就是说本题要求,求出最小的最大值. 那这样的话就暗示了将答案二分,进行check. [check方法]: 如果说 ...
- loj2425 「NOIP2015」运输计划[二分答案+树上差分]
看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\text{mid}$,然后尝试检验.````` 检验是否存在这样一个边置为0后,全部链长$\le\text{mid}$,其最终目标就是.要让所 ...
- luogu P2680 运输计划 (二分答案+树上差分)
题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间 ...
- LOJ2425 NOIP2015 运输计划 【二分+LCA+树上差分】*
LOJ2425 NOIP2015 运输计划 LINK 题意:给你一颗树,可以将任意一条边的权值变成0,然后求m条路径的长度的最小值 思路: 先二分最后的距离ans,然后我们把路程大于ans的所有路径拿 ...
- BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1930 Solved: 1231[Submit][Statu ...
- [NOIP2015]运输计划 线段树or差分二分
目录 [NOIP2015]运输计划 链接 思路1 暴力数据结构 思路2 二分树上差分 总的 代码1 代码2 [NOIP2015]运输计划 链接 luogu 好久没写博客了,水一篇波. 思路1 暴力数据 ...
- NOIP2015 运输计划 - 二分 + 树链剖分 / (倍增 + 差分)
BZOJ CodeVS Uoj 题目大意: 给一个n个点的边带权树,给定m条链,你可以选择树中的任意一条边,将它置为0,使得最长的链长最短. 题目分析: 最小化最大值,二分. 二分最短长度mid,将图 ...
随机推荐
- html初体验#2
碎碎念 关于布局 css布局:横向.纵向 2019年新进展:css grid git bash 上安装 http server 目的在于不使用 file:// 打开自己写的文件,使用 http:// ...
- 使用mysql以及连接数据库
MySQL Table of Contents 1. 安装与配置 2. 数据库与账户 3. 用户跟权限 4. 常用命令 5. 表的创建 6. 数据类型 7. 主键约束 8. 表的修改 9. 引擎(En ...
- (转)js中then方法说明
javascript中的then方法说明: then()方法是异步执行. 意思是:就是当.then()前的方法执行完后再执行then()内部的程序,这样就避免了,数据没获取到等的问题. 语法:pr ...
- MySQL中concat以及group_concat的使用
摘自:https://www.jianshu.com/p/43cb4c5d33c1 说明: 本文中使用的例子均在下面的数据库表tt2下执行: 一.concat()函数 1.功能:将多个字符串连接成一个 ...
- php数组合并用加号(+)和用array_merge()的区别
结论:用加号合并数组:既考虑数字索引的键值对,也考虑字符串索引的键值对,用前边数组的值覆盖后边的键名相同的值; 用array_merge()合并数组:只考虑字符串索引的键值对,用后边数组的值覆盖掉前面 ...
- angular 语法的应用
angular.js 一个js框架 , 是三大主流框架之一:( vue react angular ): 原先的开发:前端和后台,利用 Ajax 进行交互, 但是框架却提出了一种开发模式:mvc 这 ...
- 微信小程序的 音频 组件
audio:音频组件, api 接口为 wx.createInnerAudioContext audio 组件的属性: id:类型 字符串 audio 组件的唯一标识 src:类型 字符串 要播放音频 ...
- HashMap,ConcurrentHashMap相关知识整理
1.HashMap的存储步骤: 1.传入key和value,判断key是否为null,如果为null,则调用putForNullKey,以null作为key存储到哈希表中: 2. 然后计算key的ha ...
- pyhton2与pyhton3切换
ubuntu中默认的Python版本是Python2.X,但是现在Python的最新版本是Python3.X. 那么怎么修改ubutun系统默认的Python解释器呢? 如果没有安装,则使用以下命令安 ...
- jmeter常用性能监听器分析
jmeter中提供了很多性能数据的监听器,我们通过监听器可以来分析性能瓶颈 本文以500线程的阶梯加压测试结果来描述图表. 常用监听器 1:Transactions per Second 监听动态TP ...