运输计划

运输计划

我们考虑先预处理出 LCA、每条路径的长度。

然后发现这个问题具有二段性,所以可以使用二分。

对于<=mid的路径,我们不需要删除边;对于>mid的路径,我们需要删除至少一条边,根据题目条件,所以当且仅当删除一条。

如何求解这些>mid的路径的公共要求的路径呢?可以考虑树上差分,对于 \((u,v),d_u\leftarrow d_u+1,d_v\leftarrow d_v+1,d_{lca}\leftarrow d_{lca}-2\),这里边上的差分用下方的点表示。我们对于每个点求子树和,看那些点的点权恰好为>mid的路径数量,那么这些边就是公共边。然后我们只需要对路径最长的路径分别枚举删除一条公共边,只要有一种方案,就是合法的。注意求子树和可以利用dfs序的逆序,预处理,这样就只需要一遍迭代,无需递归了。

#include<cstdio>
#include<iostream>
#include<cassert>
#include<cstring>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while

const int N=300010,K=19,M=2*N;
int n,m,f[N][K],d[N],de[N],s[N],seq[N],tmp;
int h[N],e[M],ne[M],w[M],idx;//don't forget memset h!
void add(int a,int b,int c){
    w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
struct path{
    int a,b,p,v;
}p[N];
void dfs(int x,int fa){
    // cout<<x<<' '<<fa<<'\n';
    // assert(!d[1]);
    seq[++tmp]=x;
    de[x]=de[fa]+1;
    Ed{
        int j=e[i];
        if(j==fa)continue;
        d[j]=d[x]+w[i];
        f[j][0]=x;
        E(k, K-1)f[j][k]=f[f[j][k-1]][k-1];
        dfs(j,x);
    }
}
int lca(int a,int b){
    if(de[a]>de[b])swap(a,b);
    Re(i, K-1, 0)
        if(de[f[b][i]]>=de[a])b=f[b][i];
    if(a==b)return a;
    Re(i, K-1, 0)
        if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
    return f[a][0];
}
bool check(int mid){
    memset(s+1,0,n*4);
    int cnt=0,mx=0;
    E(i, m){
        auto[a,b,p,v]=::p[i];
        if(v>mid){
            ++s[a],++s[b],s[p]-=2;
            ++cnt;
            mx=max(mx,v);
        }
    }
    if(!cnt)return 1;
    Re(i, n, 1){
        int j=seq[i];
        s[f[j][0]]+=s[j];
    }
    E(i, n)
        if(s[i]==cnt&&mx-(d[i]-d[f[i][0]])<=mid)return 1;
    return 0;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    #endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    memset(h,-1,n*4+4);
    E(i, n-1){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    dfs(1,0);
    // E(i, n)cout<<d[i]<<' ';
    // cout<<'\n';
    E(i, m){
        int a,b;
        cin>>a>>b;
        int p=lca(a,b),v=d[a]+d[b]-d[p]*2;
        // cout<<a<<' '<<b<<' '<<p<<'\n';
        ::p[i]={a,b,p,v};
    }
    int l=0,r=3e8;
    Wh(l<r){
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    cout<<r;
    return 0;
}
posted @ 2023-10-12 13:11  wscqwq  阅读(7)  评论(0编辑  收藏  举报