BF的数据结构题单-提高组——P2680 运输计划

题解:

题目让我们找一条边变成0,然后让整个运输航线的距离总和最短。也就是最大的最短,所以可以用二分。然后我们可以知道这个边一定在最长的那条链上面所以在树上差分找到经过次数最多的那条链。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
    return f*p;}
const int maxn=300003;
struct Edge
{
    int from,to,w,id;
}p[maxn<<1];
struct query
{
    int x,y,lca,d;
}A[maxn];
int n,m,cnt,head[maxn<<1],C[maxn],dis[maxn];
int fa[maxn],depth[maxn],top[maxn],heavy[maxn],size[maxn];
int val[maxn],dnf[maxn],tot,R,L;
inline void add_edge(int x,int y,int W)//加边
{
    cnt++;
    p[cnt].from=head[x];
    head[x]=cnt;
    p[cnt].to=y;
    p[cnt].w=W;
}
inline void dfs1(int x,int f)
{
    fa[x]=f,depth[x]=depth[f]+1,size[x]=1,dnf[++tot]=x;
    for(int i=head[x];i;i=p[i].from)
    {
        int y=p[i].to;
        if(y==f)continue;
        val[y]=p[i].w;
        dis[y]=dis[x]+p[i].w;
        dfs1(y,x);
        size[x]+=size[y];
        if(!heavy[x]||size[y]>size[heavy[x]])
            heavy[x]=y;
    }
}
inline void dfs2(int x,int t)
{
    top[x]=t;
    if(!heavy[x])return ;
    dfs2(heavy[x],t);
    for(int i=head[x];i;i=p[i].from)
    {
        int y=p[i].to;
        if(y==fa[x]||y==heavy[x])continue;
        dfs2(y,y);
    }
}
inline int LCA(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(depth[top[x]]<depth[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return depth[x]<=depth[y]?x:y;
}
inline int check(int lim,int sum=0)
{
    memset(C,0,sizeof(C));
    for(int i=1;i<=m;i++)
        if(A[i].d>lim)
        {
            C[A[i].x]++,C[A[i].y]++,C[A[i].lca]-=2;
            sum++;
        }
    for(int i=n;i>=1;i--)
    {
        C[fa[dnf[i]]]+=C[dnf[i]];
        if(val[dnf[i]]>=R-lim&&C[dnf[i]]==sum)
            return 1;
    }
    return 0;
}
inline int Binary_search(int llim,int rlim,int mid=0)
{
    while(llim<rlim)
    {
        mid=(llim+rlim)>>1;
        if(check(mid))rlim=mid;
        else llim=mid+1;
    }
    return llim;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read(),w=read();
        add_edge(x,y,w);
        add_edge(y,x,w);
        L=max(L,w);
    }
    dfs1(1,0);dfs2(1,1);
    for(int i=1;i<=m;i++)
    {
        A[i].x=read(),A[i].y=read();
        A[i].lca=LCA(A[i].x,A[i].y);
        A[i].d=dis[A[i].x]+dis[A[i].y]-2*dis[A[i].lca];
        R=max(R,A[i].d);
    }
    printf("%d\n",Binary_search(R-L,R+1));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值