【题解】luoguP2680运输计划

挺难的一道题,不过质量挺高的。
luoguP2680

看到最大值最小,首先想到的是二分。
可以预处理出每个点到根节点的距离dis数组,然后求每条路径的lca和两点的距离,即dis[u]+dis[v]-2*dis[lca(u,v)]
我之前使用的是树剖LCA但是T了好多点QAQ,改了倍增就不会了。
然后使用一个比较基础(?)的算法——树上差分,用来判断mid是否是可行解。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=300005;
int n,m,tot,mlen,num,tem,ans;
int head[N],ver[2*N],nxt[2*N],w[2*N];
int t[N],dis[N],f[N][27],a[N],dep[N];

struct path
{
    int u,v,len,lc;
} p[N];

inline int get()
{
    int res=0;char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9')
    {
        res=res*10+c-'0';
        c=getchar();
    }
    return res;
}

inline void add(int x,int y,int z)
{
    ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;w[tot]=z;
}

void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1;
    for(int i=0;i<=24;i++)
        f[u][i+1]=f[f[u][i]][i];
    for(int e=head[u];e;e=nxt[e])
    {
        int v=ver[e];
        if(v==fa) continue;
        f[v][0]=u;
        a[v]=w[e];
        dis[v]=dis[u]+w[e];
        dfs(v,u);
    }
}

inline int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=24;i>=0;i--)
    {
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        if(x==y) return x;
    }
    for(int i=24;i>=0;i--)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}

void dfs3(int u,int f)
{
    for (int e = head[u]; e ; e = nxt[e])
    {
        int v=ver[e];
        if(v==f) continue;
        dfs3(v,u);
        t[u]+=t[v];
    }
    if(t[u]==num&&a[u]>tem) tem=a[u];
}

inline bool check(int x)
{
    memset(t,0,sizeof(t));
    num=tem=0;
    for (int i = 1; i <= m; i++)
        if (p[i].len>x)
        {
            t[p[i].u]++;
            t[p[i].v]++;
            t[p[i].lc]-=2;
            num++;
        }
    dfs3(1,0);
    if(mlen-tem>x) return false;
    return true;
}

int main()
{
    int x,y,z;
    n=get(),m=get();
    for (int i = 1; i < n; i++)
    {
        x=get(),y=get(),z=get();
        add(x,y,z),add(y,x,z);
    }
    dfs(1,0);
    for (int i = 1; i <= m ; i++)
    {
        p[i].u=get(),p[i].v=get();
        p[i].lc=lca(p[i].u,p[i].v);
        p[i].len=dis[p[i].u]+dis[p[i].v]-2*dis[p[i].lc];
    }
    for (int i = 1; i <= m; i++)
        mlen=max(mlen,p[i].len);
    int l=0,r=mlen,mid;
    while (l<r)
    {
        mid=(l+r)>>1;
        if (check(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d",l);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zxj-hans/p/11266941.html