[NOIP2015 提高组] 运输计划

[NOIP2015 提高组] 运输计划

0x01 题意

给定一棵树,边有权值,给定树上的若干条路径,求把一条边的权值变为0后,这些路径中的最长路径长是多少

0x02 解

答案具有单调性,所以可以二分路径长找答案

我们发现把其中一条边权变为0,这条边一定在最长路径上,如果不在最长路径上,那么答案不是最优的

所以我们check函数中,判断有没有一条边,边权为w,满足\(二分路径长>=最长路径-w\)即可

但是考虑到删掉一条边后有可能其他路径长会大于之前的最长路径成为新的最长路径

在二分时我们把大于二分路径长的路径在树上差分计数,当我们枚举到的那条边在所有大于二分路径长的路径上时,这些路径会同时减掉这条边的边权,这样就避免了其他路径成为最长路径

0x03 码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
using namespace std;
const int INF=0x3f3f3f3f,N=300010;

inline int read(){
    int x=0,y=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*y;
}

int e[4*N],ne[4*N],w[4*N],h[N],idx;
int f[N],d[N],siz[N],ms[N],top[N],id[N],rk[N],cnt=0,sum=0,val[N],dis[N];
int n,m;
int qa[N],qb[N],qlca[N],qd[N],maxd,maxl;
int buc[N];

void add(int a,int b,int c){
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}

void dfs1(int x,int fa){
    f[x]=fa;
    d[x]=d[fa]+1;
    siz[x]=1;
    for(int i=h[x];~i;i=ne[i]){
        int j=e[i];
        if(j==fa) continue;
        dis[j]=dis[x]+w[i];
        val[j]=w[i];
        dfs1(j,x);
        siz[x]+=siz[j];
        if(!ms[x]||siz[ms[x]]<siz[j]) ms[x]=j;
    }
}

void dfs2(int x,int topp){
    top[x]=topp;id[x]=++cnt,rk[cnt]=x;
    if(!ms[x]) return;
    dfs2(ms[x],topp);
    for(int i=h[x];~i;i=ne[i]){
        int j=e[i];
        if(j==f[x]||j==ms[x]) continue;
        dfs2(j,j);
    }
}

int lca(int a,int b){
    while(top[a]!=top[b]){
        if(d[top[a]]<d[top[b]]) swap(a,b);
        a=f[top[a]];
    }
    return d[a]<=d[b]?a:b;
}

bool check(int x){
    memset(buc,0,sizeof buc);
    sum=0;
    for(int i=1;i<=m;i++){
        if(qd[i]>x){
            buc[qa[i]]++;
            buc[qb[i]]++;
            buc[qlca[i]]-=2;
            sum++;
        }
    }
    for(int i=n;i>=1;i--){
        buc[f[rk[i]]]+=buc[rk[i]];
        if(val[rk[i]]>=maxd-x&&buc[rk[i]]==sum){
            return 1;
        }
    }
    return 0;
}

int biss(int a,int b){
    int l=a,r=b;
    while(l<r){
        int mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    return l;
}

int main(){

    memset(h,-1,sizeof h);
    
    n=read();
    m=read();
    for(int i=1;i<n;i++){
        int a,b,t;
        a=read(),b=read(),t=read();
        add(a,b,t);
        add(b,a,t);
        maxl=max(maxl,t);
    }
    dfs1(1,0),dfs2(1,1);
    for(int i=1;i<=m;i++){
        qa[i]=read(),qb[i]=read();
        qlca[i]=lca(qa[i],qb[i]);
        qd[i]=dis[qa[i]]+dis[qb[i]]-2*dis[qlca[i]];
        maxd=max(maxd,qd[i]);
    }

    int ans=biss(maxd-maxl,maxd+1);

    cout<<ans;

    return 0;
}
posted @ 2021-07-01 17:40  wsy_jim  阅读(89)  评论(0编辑  收藏  举报