1. 程式人生 > 其它 >[NOIP2015 提高組] 運輸計劃

[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;
}