NOIp 2015 运输计划 LCA

运输计划

问题大意

有n个星球与n-1条双向边,每条边有时间ti,有m个从vi到ui的运输计划。允许你将一条边的时间降为0。同时开始所有的计划,问最小要多少时间完成计划。

输入输出格式

输入格式:

输入文件名为 transport.in。

第一行包括两个正整数 n、m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。

接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai, bi 和 ti,表示第

i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。

接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j个 运输计划是从 uj 号星球飞往 vj 号星球。

输出格式:

输出 共1行,包含1个整数,表示小P的物流公司完成阶段性工作所需要的最短时间。

样例输入输出

input

6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5

output

11

数据规模

 n<=300000 m<=300000   1<=a,b,u,v<=n  0<=ti<=1000

解题报告

这一题一眼看出来就是二分答案。关键是怎么检查。这里我们可以用一个小小的贪心。如果枚举的t大与某些计划原本需要的时间,我们可以记下这些计划,如果要去掉一个边的时间,我们肯定要去掉这些超时计划的所有路径的公共边,只有是公共边,才有同时让这些计划不超时的可能。如果去掉一条公共边,能使得耗时最长的计划不超时,就满足要求。

那么,如何找公共边呢?我们可以用树的差分来实现。简单说一下,首先开一个数组tmp,如果有一条路径从vi到ui,那么我们就tmp[vi]++,tmp[ui++],tmp[lca(vi,ui)]-=2;之后,就用一遍dfs,将tmp[]数组进行dfs序的累加。如果有一个tmp[i]的值等于超时点的数量,那么从i到i的父亲的那一条边就算公共边(证明就不说啦,不难)。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstring>
#include <climits>
#define MAXN 300000+10
#define MAXM 300000+10
using namespace std;
int n,m,head[MAXN],deep[MAXN],dis[MAXN][50],fa[MAXN][50],num;
int p[MAXM],pa[MAXN],tmp[MAXN],root=1,s[MAXN],t[MAXN],all;
bool vis[MAXN];
struct Edge{
    int dis,from,to,next;
}edge[MAXN<<1];
void add(int from,int to,int dis)
{
    edge[++num].next=head[from];
    edge[num].from=from;
    edge[num].to=to;
    edge[num].dis=dis;
    head[from]=num;
}
void dfs(int x)
{
    for(int i=head[x];i;i=edge[i].next)
    if(!deep[edge[i].to])
    {
        deep[edge[i].to]=deep[x]+1;
        fa[edge[i].to][0]=x;
        dis[edge[i].to][0]=edge[i].dis;
        dfs(edge[i].to);
    }
}
void dfs2(int x)
{    
    int ans=0;
    for(int i=head[x];i;i=edge[i].next)
    if(!vis[edge[i].to])
    {
        vis[edge[i].to]=1;
        dfs2(edge[i].to);
        ans+=tmp[edge[i].to];
    }
    tmp[x]+=ans;
}
void init()
{
    deep[root]=1;
    dfs(root);
    for(int j=0;(1<<j)<=n;j++)
        for(int i=1;i<=n;i++)
            if(fa[i][j-1])    
                fa[i][j]=fa[fa[i][j-1]][j-1],
                dis[i][j]=dis[i][j-1]+dis[fa[i][j-1]][j-1];
}
int lca(int a,int b,int no)
{
    if(deep[a]>deep[b]) swap(a,b);
    int d=deep[b]-deep[a],ans=0;
    for(int j=0;(1<<j)<=d;j++)
    if((1<<j)&d)
    {
        ans+=dis[b][j];
        b=fa[b][j];
    }
    if(a==b) {pa[no]=a;return ans;}
    for(int j=log2(n);j>=0;j--)
    if(fa[a][j]!=fa[b][j])
    {
        ans+=dis[a][j]+dis[b][j];
        a=fa[a][j];b=fa[b][j];
    }
    pa[no]=fa[a][0];
    return ans+dis[a][0]+dis[b][0];
}
bool check(int ti)
{
    memset(tmp,0,sizeof tmp);
    int num=0;
    memset(vis,0,sizeof vis);
    int maxx=0,maxp=0,maxm=0;
    for(int i=1;i<=m;i++)
    {
        if(p[i]>ti)
        {    
            num++;
            tmp[s[i]]++;tmp[t[i]]++;
            tmp[pa[i]]-=2;
            maxm=max(maxm,p[i]-ti);
        }
    }
    vis[1]=1;
    dfs2(1);
    for(int i=1;i<=n;i++)
        if(tmp[i]==num&&dis[i][0]>=maxm)
            return 1;
    return 0;
}
void er()
{
    int l=0,r=all,m;
    while(l<r-1)
    {
        m=(l+r)>>1;
        if(check(m)) r=m;
        else l=m;
    }
    if(check(l)) printf("%d\n",l);
    else printf("%d\n",r);
}
int read(){
    int in=0;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar())in=in*10+ch-'0';
    return in;
}
int main()
{

    n=read();m=read();
  int x,y,z;
  for(int i=1;i<n;i++)
  {
        x=read();y=read();z=read();
      all+=z;
      add(x,y,z);
      add(y,x,z);
  }
  init();
  for(int i=1;i<=m;i++)
  {
      //scanf("%d%d",&s[i],&t[i]);
      s[i]=read();t[i]=read();
      p[i]=lca(s[i],t[i],i);
  }
  er();

  return 0;
}

 

 

 

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值