题目连接:https://www.luogu.com.cn/problem/P2680
题目大意:




如果X时间可以完成,那么Y>X时间一定可以完成。满足单调性,二分时间。

对于一个时间mid。比mid大的k条路径都必须经过一次拆边变得<=mid。那么这条边一个经过这k条路径。这个用树上边差分判断。在所有经过这k条路径的边中找到最大的一条ans。如果这前k条路径-ans<=mid。L=mid+1。
否则: R=mid-1。

#include <bits/stdc++.h>
#define LL long long
using namespace std;

struct node{
    int to, c;
};
vector<node> v[300005];
//深度 //倍增 //s: 和根节点的距离 c:差分数组 fs:第i个节点代表的那条边
int d[300005], f[300005][25], lg[300005], s[300005], c[300005], fs[300005];
int tot;

struct eg{
    int u, to, s;
};

vector<eg> e;

void dfs(int u, int fa){

    d[u]=d[fa]+1;
    f[u][0]=fa;
    for(int i=1; (1<<i)<=d[u]; i++){
        f[u][i]=f[f[u][i-1]][i-1];
    }
    for(int i=0; i<v[u].size(); i++){
        if(v[u][i].to!=fa){
            s[v[u][i].to]=s[u]+v[u][i].c;
            dfs(v[u][i].to, u);
            fs[v[u][i].to]=v[u][i].c;
        }
    }
}

int LCA(int x ,int y){
    if(d[x]<d[y]){
        swap(x, y);
    }
    while(d[x]!=d[y]){
        x=f[x][lg[d[x]-d[y]]-1];
    }
    if(x==y){
        return x;
    }
    for(int k=lg[d[x]]; k>=0; k--){
        if(f[x][k]!=f[y][k]){
            x=f[x][k], y=f[y][k];
        }
    }
    return f[x][0];
}

int cmp(eg a, eg b){
    return a.s>b.s;
}

int ans=0;

void get_max(int u, int fa, int k){//得到是前k条路径都经过的边的最大值
    for(int i=0; i<v[u].size(); i++){
        int to=v[u][i].to;
        if(to!=fa){
            get_max(to, u, k);
            c[u]+=c[to];
            c[to]=0;//初始化回去
        }
    }
    if(c[u]==k){
        ans=max(fs[u], ans);
    }
}

int slove(int mid, int n){
    int k=e.size();
    for(int i=0; i<e.size(); i++){//找到比mid大的k条边
        if(e[i].s<=mid){
            k=i;
            break;
        }
    }
    for(int i=0; i<k; i++){//树上边差分
        int a=e[i].u, b=e[i].to;
        c[a]++, c[b]++, c[LCA(a, b)]-=2;
    }
    ans=0;
    get_max(1, 0, k);//找到经过这k条路径边的最大值
    for(int i=0; i<k; i++){
        if(e[i].s-ans>mid){
            return 0;
        }
    }
    return 1;
}

int main(){

    int n, m, a, b, c;
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++) {//预处理
        lg[i]=lg[i-1];
        if(i==1<<lg[i-1])lg[i]++;
    }

    for(int i=1; i<n; i++){
        scanf("%d%d%d", &a, &b, &c);
        v[a].push_back(node{b, c});
        v[b].push_back(node{a, c});
    }
    s[1]=0;
    dfs(1,0);//从树根开始dfs
    for(int i=1; i<=m; i++){
        scanf("%d%d", &a, &b);
        e.push_back(eg{a, b, s[a]+s[b]-2*s[LCA(a, b)]});
    }
    sort(e.begin(), e.end(), cmp);
    
    //L:边的最大值为1000, 所以路径最多减小1000
    //还有,不加这个优化会T掉一个点(各种 卡常+优化 都过不去
    int R=e[0].s, L=max(0, R-1000), k;
    
    while(L<=R){
        int mid=(L+R)/2;
        if(slove(mid, n)){
            R=mid-1; k=mid;
        }
        else{
            L=mid+1;
        }
    }
    printf("%d\n", k);

    return 0;
}