题目大意: 给你一棵n个节点的树,有边权,有多个任务,每个要求从ui号节点到 vi号节点去。m 个计划, 这 m 个计划会同时开始。当这 m 个任务都完成时,工作完成。

现在可以把任意一个边的边权变为0,试求出完成工作所需要的最短时间是多少?

题解:先求出每个任务原来的所需时间,一种想法是枚举改变哪条边,但这肯定会超时(不然怎么是T3),然后我们可以想到,我们可以发现必须把最长的时间缩短,才可以把答案时间缩短,于是我们可以用二分它完成的时间,然后进行判断,把时间超过这个二分答案的任务记录一下,然后可以发现,我们要减少其中所有任务都经过的边才可以把所有任务的时间变短。

那该怎么做呢?就要用树上差分了(节点版),我们用一个数组存每个节点的差分值,它的子树的值的和就是它所要经过的次数,假设任务是从a->b,就可以s[a]++,s[b]++,s[lca(a,b)]-=2(lca要存下来,不然也会超时),具体可以baidu。

C++ Code:

#include<cstdio>
#include<cstring>
#define maxn 300100
#define maxm 21
#define inf 0x7ffffff
using namespace std;
int cnt,head[maxn];
int n,m,ans=inf;
int s[maxn],e[maxn];
int lca[maxn],deep[maxn],fa[maxn][maxm],sum[maxn],sum2[maxn];
int p[maxn];
struct Edge{
int to,nxt,cost;
}edge[maxn<<1];
void add(int a,int b,int c){
cnt++;
edge[cnt].to=b;
edge[cnt].nxt=head[a];
edge[cnt].cost=c;
head[a]=cnt;
}
void dfs(int root){
for (int i=head[root];i;i=edge[i].nxt){
int ne=edge[i].to;
if (deep[ne]==0){
deep[ne]=deep[root]+1;
sum[ne]=sum[root]+edge[i].cost;
fa[ne][0]=root;
dfs(ne);
}
}
}
void init(){
for (int i=1;i<maxm;i++){
for (int j=1;j<=n;j++){
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
}
int LCA(int x,int y){
if (deep[x]<deep[y])x^=y^=x^=y;
for (int i=maxm-1;i>=0;i--){
if (deep[fa[x][i]]>=deep[y]){
x=fa[x][i];
}
}
if (x==y)return x;
for (int i=maxm-1;i>=0;i--){
if (fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
void dfs1(int root){
if (head[root]==0)return;
for (int i=head[root];i;i=edge[i].nxt){
int ne=edge[i].to;
if (deep[ne]==deep[root]+1){
dfs1(ne);
p[root]+=p[ne];
}
}
}
bool check(int mid){
int maxo=0,num=0;
memset(p,0,sizeof(p));
for (int i=1;i<=n;i++){
if (sum2[i]>mid){
num++;
if (maxo<(sum2[i]-mid))maxo=sum2[i]-mid;
p[s[i]]++;
p[e[i]]++;
p[lca[i]]-=2;
}
}
dfs1(1);
for (int i=1;i<=n;i++){
if (p[i]==num){
if (sum[i]-sum[fa[i][0]]>=maxo)return 1;
}
}
return 0;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
deep[1]=1;
dfs(1);
init();
int r=0;
for (int i=1;i<=m;i++){
scanf("%d%d",&s[i],&e[i]);
lca[i]=LCA(s[i],e[i]);
sum2[i]=(sum[s[i]]+sum[e[i]]-(sum[lca[i]]<<1));
if(sum2[i]>r)r=sum2[i];
}
int l=0;
while (l<=r){
int mid=l+r>>1;
if (check(mid)){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
printf("%d\n",ans);
return 0;
}

[NOIP2015 TG D2T3]运输计划的更多相关文章

  1. NOIP2015 提高组] 运输计划

    码农题啊兄弟们. 随便考虑二分一下,然后发现要取一条满足性质的边. 被所有大于\(mid\)的路径都覆盖,取了之后能把他们都弄到小于\(mid\) 那就树上差分再处理一下. 写了\(180h\),老年 ...

  2. [NOIP2015 提高组] 运输计划题解

    题目链接:P2680 [NOIP2015 提高组] 运输计划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 看了好长时间题解才终于懂的,有关lca和二分答案的题解解释的不详细,一时 ...

  3. [NOIP 2015TG D2T3] 运输计划

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...

  4. [NOIP2015提高组]运输计划

    题目:BZOJ4326.洛谷P2680.Vijos P1983.UOJ#150.codevs4632.codevs5440. 题目大意:有一棵带权树,有一些运输计划,第i个运输计划从ai到bi,耗时为 ...

  5. NKOJ 【NOIP2015 Day2】运输计划

    时间限制 : 20000 MS   空间限制 : 262144 KB 评测说明 : 2s,256m 问题描述 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n−1 条双向航道, ...

  6. NOIP2015 D2T3 运输计划

    拿到题目的第一眼 首先这是一棵n个节点的树(别说你看不出来) 然后对于树上的m条链我们可以选取树上的唯一一条边使它的边权变为0 求处理后最长链的长度 20分 m=1好啦,好像可做一眼望去全是水 只需求 ...

  7. 洛谷 P2680 [NOIP2015 提高组] 运输计划

    链接:P2680 题意: 在树上把一条边边权变为0使得最长给定路径最短 分析: 最大值最小可以想到二分答案,对于每一个mid,寻找所有大于mid的路径,再寻找是否存在一条边使得删去它后大于mid的路径 ...

  8. P2680 [NOIP2015 提高组] 运输计划 (树上差分-边差分)

    P2680 题目的大意就是走完m条路径所需要的最短时间(边权是时间), 其中我们可以把一条边的权值变成0(也就是题目所说的虫洞). 可以考虑二分答案x,找到一条边,使得所有大于x的路径都经过这条边(差 ...

  9. [NOIP 2015]运输计划-[树上差分+二分答案]-解题报告

    [NOIP 2015]运输计划 题面: A[NOIP2015 Day2]运输计划 时间限制 : 20000 MS 空间限制 : 262144 KB 问题描述 公元 2044 年,人类进入了宇宙纪元. ...

随机推荐

  1. Ubentu下命令行安装chrome浏览器

    前言: 最近在使用Ubuntu 系统.编译Android aosp 项目.准备写博客,但是Ubuntu 的默认浏览器 firefox 在写csdn 的时候,加载不出来.如下图 一直卡在这里. 这种情况 ...

  2. C#防止程序重新运行

    //禁止重复运行 bool ret; Mutex mutex = new Mutex(true, Application.ProductName, out ret); if (ret) { Appli ...

  3. VINS(三)IMU预积分

    IMU的数据频率一般远高于视觉,在视觉两帧k,k+1之间通常会有>10组IMU数据.IMU的数据通过积分,可以获取当前位姿(p位置,q四元数表达的姿态).瞬时速度等参数. 在VIO中,如果参考世 ...

  4. OpenCV 3.2 Viz 3D可视化

    该可视化模块提供了坐标系变化,3D动画等功能 最简单的显示坐标系 viz::Viz3d window("window"); window.showWidget("Coor ...

  5. 三分钟小课堂-----------------docker(三)增删改查命令

    主要为docker容器的增删改查命令 1  创建容器: docker run   -it   --name 别名  image_name   /bin/bash --name 别名 -d 后台 -t ...

  6. Linux命令应用大词典-第13章 用户和组群管理

    13.1 useradd:创建用户账户 13.2 adduser:创建用户账户 13.3 lnewusers:创建用户账户 13.4 usermod:修改用户账户 13.5 userdel:删除用户账 ...

  7. 01背包问题:DP

    题目描述: 有 N 件物品和一个容量是 V 的背包.每件物品只能使用一次. 第 i 件物品的体积是 vi,价值是 wi. 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大.输出 ...

  8. leetcode个人题解——#20 Valid Parentheses

    class Solution { public: bool isValid(string s) { stack<char> brackts; ; i < s.size(); i++) ...

  9. nodejs笔记--基础篇(一)

    Sublime Node.js开发环境配置 下载并安装Node.js安装包后再开始配置 1.先安装好Sublime Text 2 2.运行Sublime,菜单上找到Tools ---> Buil ...

  10. rewrite or internal redirection cycle while processing nginx重定向报错

    2018/05/07 15:03:42 [error] 762#0: *3 rewrite or internal redirection cycle while processing "/ ...