[NOIP2015]运输计划

[NOIP2015]运输计划https://www.luogu.org/problemnew/show/P2680

题目背景

公元 \(2044\) 年,人类进入了宇宙纪元。

题目描述

\(L\) 国有 \(n\) 个星球,还有 \(n-1\) 条双向航道,每条航道建立在两个星球之间,这 \(n-1\) 条航道连通了 \(L\) 国的所有星球。
\(P\) 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 \(u_i\) 号星球沿最快的宇航路径飞行到 \(v_i\) 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 \(j\),任意飞船驶过它所花费的时间为 \(t_j\),并且任意两艘飞船之 间不会产生任何干扰。
为了鼓励科技创新, \(L\) 国国王同意小 \(P\) 的物流公司参与 \(L\) 国的航道建设,即允许小 \(P\) 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 \(P\) 的物流公司就预接了 \(m\) 个运输计划。在虫洞建设完成后, 这 \(m\) 个运输计划会同时开始,所有飞船一起出发。当这 \(m\) 个运输计划都完成时,小 \(P\) 的 物流公司的阶段性工作就完成了。
如果小 \(P\) 可以自由选择将哪一条航道改造成虫洞,试求出小 \(P\) 的物流公司完成阶段性工作所需要的最短时间是多少?

输入格式:

输入文件名为 \(transport.in\)
第一行包括两个正整数 \(n、m\),表示 \(L\) 国中星球的数量及小 \(P\) 公司预接的运输计划的数量,星球从 \(1\)\(n\) 编号。
接下来 \(n-1\) 行描述航道的建设情况,其中第 \(i\) 行包含三个整数 \(a_i, b_i\)\(t_i\)表示第
\(i\) 条双向航道修建在 \(a_i\)\(b_i\) 两个星球之间,任意飞船驶过它所花费的时间为 \(t_i\)
接下来 \(m\) 行描述运输计划的情况,其中第 \(j\) 行包含两个正整数 \(u_j\)\(v_j\),表示第 \(j\)个 运输计划是从 \(u_j\) 号星球飞往 \(v_j\) 号星球。

输出格式:

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

输入样例:

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

输出样例:

11

说明

\(n,m<=300000\)
\(1<=a_i,b_i,u_j,v_j<=n\)
\(t_i<=1000\)
请注意常数因子带来的程序效率上的影响。


由题面信息可知,我们要删除一条边,使所有计划用时的最大值最小.
不难猜出是要二分答案的.
左端点\(L=0\),右段点\(R=\)所有计划中用时的最大值\(Maxlen\).
因此先预处理出每个运输计划的用时[求LCA]
二分出一个\(mid\)
那么所有用时大于\(mid\)的计划都是不合法的,这些路径必须作出改动,因此删掉的边应为它们的公共边.
如果树剖维护每条边被不合法计划经过的次数,
那么被删的那条边一定被每个不合法计划都经过
找出这些边
对于某条边,设边权为\(val\),并检验

\[Maxlen-val<=mid \]

如果有一条边能满足条件,则有解,返回\(true\)
否则返回\(false\)
建议:
树剖用树状数组,线段树常数大卡掉\(5\)分,树状数组开\(O2\)可过.

#define RG register
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e5+5;
inline int read()
{
    RG int x=0,w=1;RG char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}
int n,m,ct,cnt,L,R,Ans;
int last[N],dep[N],top[N],son[N],dfn[N],size[N],f[N][25],dist[N][25],sum[N];
struct edge{int to,next,w;}e[N<<1];
struct node{int val,u,v;}lca[N];
inline bool cmp(node a,node b){return a.val<b.val;}
inline int lowbit(int x){return (-x)&x;}
inline void insert(int u,int v,int w)
{
    e[++cnt]=(edge){v,last[u],w};last[u]=cnt;
    e[++cnt]=(edge){u,last[v],w};last[v]=cnt;
}
void dfs1(int now)
{
    size[now]=1;
    for(int i=last[now];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f[now][0])continue;
        dep[v]=dep[now]+1;
        f[v][0]=now;
        dist[v][0]=e[i].w;
        dfs1(v);
        size[now]+=size[v];
        if(size[v]>size[son[now]])son[now]=v;
    }
}
void dfs2(int now,int Top)
{
    top[now]=Top;dfn[now]=++ct;
    if(son[now])dfs2(son[now],Top);
    for(RG int i=last[now];i;i=e[i].next)
    {
        RG int v=e[i].to;
        if(v==f[now][0]||v==son[now])continue;
        dfs2(v,v);
    }
}
inline void init()
{
    dep[1]=1;
    dfs1(1);
    dfs2(1,1);
    for(RG int j=1;j<=20;j++)
        for(RG int i=1;i<=n;i++)
        {
            f[i][j]=f[f[i][j-1]][j-1];
            dist[i][j]=dist[i][j-1]+dist[f[i][j-1]][j-1];
        }
}
inline int Lca(int x,int y)
{
    RG int Sum=0;
    if(dep[y]>dep[x])swap(x,y);
    for(RG int i=20;i>=0;i--)if(f[x][i]&&dep[f[x][i]]>=dep[y])Sum+=dist[x][i],x=f[x][i];
    if(x==y)return Sum;
    for(RG int i=20;i>=0;i--)
        if(f[x][i]&&f[y][i]&&f[x][i]!=f[y][i])
        {
            Sum+=dist[x][i]+dist[y][i];
            x=f[x][i];y=f[y][i];
        }
    Sum+=dist[x][0]+dist[y][0];
    return Sum;
}
inline void Modify(int x,int k)
{
    while(x<=n)sum[x]+=k,x+=lowbit(x);
}
inline int Query(int x)
{
    RG int Ans=0;
    while(x)Ans+=sum[x],x-=lowbit(x);
    return Ans;
}
inline void Modify_Tree(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        Modify(dfn[top[x]],1);Modify(dfn[x]+1,-1);
        x=f[top[x]][0];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)Modify(dfn[x]+1,1),Modify(dfn[y]+1,-1);
}
inline bool check(int k)
{
    memset(sum,0,sizeof(sum));
    RG int Num=0;
    for(RG int i=m;i>=1;i--)
    {
        if(lca[i].val>k)Num++,Modify_Tree(lca[i].u,lca[i].v);
        else break;
    }
    for(RG int i=1;i<=n;i++)if(Query(dfn[i])==Num&&lca[m].val-dist[i][0]<=k)return true;
    return false;
}
int main()
{
    n=read();m=read();
    for(RG int i=1;i<n;i++)
    {
        RG int a=read(),b=read(),c=read();
        insert(a,b,c);
    }
    init();
    for(RG int i=1;i<=m;i++)
    {
        lca[i].u=read();lca[i].v=read();
        lca[i].val=Lca(lca[i].u,lca[i].v);
    }
    sort(lca+1,lca+m+1,cmp);
    R=lca[m].val;
    while(L<=R)
    {
        RG int mid=(L+R)>>1;
        if(check(mid))Ans=mid,R=mid-1;
        else L=mid+1;
    }
    printf("%d\n",Ans);
    return 0;
}
posted @ 2018-03-23 22:28  sdzwyq  阅读(162)  评论(0编辑  收藏  举报