Description

Input

Output

Sample Input

6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5

Sample Output

11

 

Data Constraint

 

这道题lca可以拿60分.

枚举每条边变为黑洞,求最小的里程判断这条边是否在u到v的路径上

复杂度O(n*m)

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5;
struct X
{
    int v,q,f,n;
}x[N<<1];
int s=1,qd[N],zd[N],dep[N],fir[N],ol[N<<1][17],cnt,d[N],dfn[N];
bool vis[N];
void add(int u,int v,int q)
{
    x[++s].n=x[u].f;
    x[x[u].f=s].v=v;
    x[s].q=q;
}
void dfs(int u)
{
    vis[dfn[++s]=u]=1;
    ol[fir[u]=++cnt][0]=s;
    int t=s;
    for(int i=x[u].f;i;i=x[i].n)
        if(!vis[x[i].v])
        {
            dep[x[i].v]=dep[u]+1;
            d[x[i].v]=d[u]+x[i].q;
            dfs(x[i].v);
            ol[++cnt][0]=t;
        }
}
int lca(int l,int r)
{
    int k=0;l=fir[l];r=fir[r];
    if(l>r) swap(l,r);
    for(;1<<(k+1)<=r-l+1;k++);
    return dfn[min(ol[l][k],ol[r-(1<<k)+1][k])];
}
int main()
{
    int n,m,ans=1e9;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int u,v,q;
        scanf("%d%d%d",&u,&v,&q);
        add(u,v,q);add(v,u,q);
    }
    for(int i=1;i<=m;i++)
        scanf("%d%d",&qd[i],&zd[i]);
    s=0;dfs(1);
    for(int j=1;1<<j<=cnt;j++)
        for(int i=1;i+(1<<j)-1<=cnt;i++)
            ol[i][j]=min(ol[i][j-1],ol[i+(1<<j-1)][j-1]);
    for(int i=1;i<n;i++)
    {
        int u=x[i<<1].v,v=x[i<<1|1].v,tans=0;
        if(dep[u]<dep[v]) swap(u,v);
        for(int j=1;j<=m;j++)
        {
            int t=lca(qd[j],zd[j]),dis=d[qd[j]]+d[zd[j]]-d[t]*2;
            if(dep[t]<=dep[v]&&max(dep[qd[j]],dep[zd[j]])>=dep[u])
            {
                int lc1=lca(qd[j],u),lc2=lca(qd[j],v),lc3=lca(zd[j],u),lc4=lca(zd[j],v);
                if((lc1==u&&lc2==v)||(lc3==u&&lc4==v)) dis-=x[i<<1].q;
            }
            tans=max(dis,tans);
        }
        ans=min(ans,tans);
    }
    printf("%d",ans);
    return 0;
}

80分对于链的情况进行特判。

对于链的情况进行二分。

check函数:对于所有大于x的路径在差分数组里标记。

如果差分数组中的数达到大于x的路径数且修改这条路可以使最大路径<mid即可以返回1

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5;
struct X
{
    int v,q,f,n;
}x[N<<1];
int s=1,qd[N],zd[N],dep[N],fir[N],ol[N<<1][17],cnt,d[N],dfn[N],n,m;
bool vis[N];
void add(int u,int v,int q)
{
    x[++s].n=x[u].f;
    x[x[u].f=s].v=v;
    x[s].q=q;
}
void dfs(int u)
{
    vis[dfn[++s]=u]=1;
    ol[fir[u]=++cnt][0]=s;
    int t=s;
    for(int i=x[u].f;i;i=x[i].n)
        if(!vis[x[i].v])
        {
            dep[x[i].v]=dep[u]+1;
            d[x[i].v]=d[u]+x[i].q;
            dfs(x[i].v);
            ol[++cnt][0]=t;
        }
}
int lca(int l,int r)
{
    int k=0;l=fir[l];r=fir[r];
    if(l>r) swap(l,r);
    for(;1<<(k+1)<=r-l+1;k++);
    return dfn[min(ol[l][k],ol[r-(1<<k)+1][k])];
}
bool f(int a)
{
    int mx=0,sl=0;
    memset(dep,0,sizeof(dep));
    for(int i=1;i<=m;i++)
        if(d[zd[i]]-d[qd[i]]>a) ++dep[qd[i]],--dep[zd[i]],++sl,mx=max(mx,d[zd[i]]-d[qd[i]]);
    if(!mx) return 0;
    for(int i=1,lj=0;i<=n;i++)
    {
        lj+=dep[i];
        if(lj==sl&&x[i<<1].q+a>=mx) return 0;
    }
    return 1;
}
int main()
{
    int ans=1e9;
    bool pd=1;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int u,v,q;
        scanf("%d%d%d",&u,&v,&q);
        add(u,v,q);add(v,u,q);
        if((u==i&&v==i+1)||(v==i&&u==i+1));
        else pd=0;
    }
    for(int i=1;i<=m;i++)
        scanf("%d%d",&qd[i],&zd[i]);
    if(pd)
    {
        int l=0,r=0;
        for(int i=2;i<=n;i++)
            d[i]=d[i-1]+x[(i-1)<<1].q;
        for(int i=1;i<=m;i++)
        {
            if(qd[i]>zd[i]) swap(qd[i],zd[i]);
            r=max(r,d[zd[i]]-d[qd[i]]);
        }
        while(l<r-1)
        {
            int mid=(l+r)>>1;
            if(f(mid)) l=mid;
            else r=mid;
        }
        printf("%d",r);
        return 0;
    }
    s=0;dfs(1);
    for(int j=1;1<<j<=cnt;j++)
        for(int i=1;i+(1<<j)-1<=cnt;i++)
            ol[i][j]=min(ol[i][j-1],ol[i+(1<<j-1)][j-1]);
    for(int i=1;i<n;i++)
    {
        int u=x[i<<1].v,v=x[i<<1|1].v,tans=0;
        if(dep[u]<dep[v]) swap(u,v);
        for(int j=1;j<=m;j++)
        {
            int t=lca(qd[j],zd[j]),dis=d[qd[j]]+d[zd[j]]-d[t]*2;
            if(dep[t]<=dep[v]&&max(dep[qd[j]],dep[zd[j]])>=dep[u])
            {
                int lc1=lca(qd[j],u),lc2=lca(qd[j],v),lc3=lca(zd[j],u),lc4=lca(zd[j],v);
                if((lc1==u&&lc2==v)||(lc3==u&&lc4==v)) dis-=x[i<<1].q;
            }
            tans=max(dis,tans);
        }
        ans=min(ans,tans);
    }
    printf("%d",ans);
    return 0;
}

100分:

同样进行二分,对于树上的点在d[u]++,d[v]++,d[lca(u,v)]-=2;所以i到fa[i]的路径覆盖数为sum(d[j])j为所有i的子节点。

ps:由于此题卡常数可能并不能在所有oj ac

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3*1e5+5;
struct X
{
    int v,q,f,n;
}x[N<<1],y[N<<1];
int s=1,r,cnt,d[N],fa[N],n,m,mx,lc[N<<1];
bool vis[N];
void add(int u,int v,int q,X *t)
{
    t[++s].n=t[u].f;
    t[t[u].f=s].v=v;
    t[s].q=q;
}
int find(int a)
{
    int b=a;
    while(fa[b]) b=fa[b];
    while(a!=b)
    {
        int t=fa[a];
        fa[a]=b;
        a=t;
    }
    return b;
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=x[u].f;i;i=x[i].n)
        if(!vis[x[i].v])
        {
            d[x[i].v]=d[u]+x[i].q;
            dfs(x[i].v);
            fa[x[i].v]=u;
        }
    for(int i=y[u].f;i;i=y[i].n)
        if(vis[y[i].v])
        {
            lc[i]=lc[i^1]=find(y[i].v);
            y[i].q=y[i^1].q=d[y[i].v]+d[u]-(d[lc[i]]<<1);
            r=max(r,y[i].q);
        }
}
bool dfs1(int u,int fa,int a)
{
    for(int i=x[u].f;i;i=x[i].n)
        if(x[i].v!=fa)
        {
            if(!dfs1(x[i].v,u,a))  return 0;
            if(d[x[i].v]==cnt&&a+x[i].q>=mx) return 0;
            d[u]+=d[x[i].v];
        }
    return 1;
}
bool f(int a)
{
    mx=cnt=0;
    memset(d,0,sizeof(d));
    for(int i=1;i<=m;++i)
        if(y[i<<1].q>a) 
        {
            ++d[y[i<<1].v];
            ++d[y[i<<1|1].v];
            d[lc[i<<1]]-=2;
            ++cnt;mx=max(mx,y[i<<1].q);
        }
    if(!cnt) return 0;
    return dfs1(1,0,a);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;++i)
    {
        int u,v,q;
        scanf("%d%d%d",&u,&v,&q);
        add(u,v,q,x);add(v,u,q,x);
    }
    s=1;int l=0;
    for(int i=1;i<=m;++i)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v,0,y);add(v,u,0,y);
    }
    dfs(1);
    while(l<r-1)
    {
        int mid=(l+r)>>1;
        if(f(mid)) l=mid;
        else r=mid;
    }
    printf("%d",r);
    return 0;
}