【图论】【LCA】NOIP2015运输计划

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/82628021

分析:

mmp出题人太垃圾了
尼玛树链剖分 O ( N l o g 2 N ) 的算法跑得飞快,用LCA严格 O ( N l o g N ) 的最后一个点却被卡了。

就因为出题人也写的树链剖分!所以他造的大数据就按着他不会T为标准。所以搞出来的数据用树链剖分或类似的方法都跑得飞快。

但我还是写一下只用 L C A 的算法吧。。。
首先,如果加速的边有贡献,其必然加速了长度最大的一条路径。

所以在最大的路径上找边权最大的边,然后答案就是:max(最大路径长-最大边权,次大路径长)

若加速的边也在次大路径中,那么答案就跟新一个:max(最大路径长-公共路径最大边权,第三大路径长)

依次这么做下去,直到相交部分为空为止。

路径求交可以用lca水过去。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 300010
using namespace std;
void Read(int &x){
    x=0;
    char c;
    while(c=getchar(),c!=EOF&&(c<'0'||c>'9'))
        continue;
    x=c-'0';
    while(c=getchar(),c!=EOF&&c>='0'&&c<='9')
        x=x*10+c-'0';
}

int n,m;
int fa[MAXN][20],deep[MAXN],len[MAXN][20],maxl[MAXN][20];
int val[MAXN],dist[MAXN];
int head[MAXN],nxt[MAXN*2],vax[MAXN*2],px[MAXN*2],cnt;
void add_edge(int x,int y,int va){
    cnt++;
    nxt[cnt]=head[x];
    px[cnt]=y;
    vax[cnt]=va;
    head[x]=cnt;
}
struct node{
    int u,v,val,lcax;
    bool operator < (const node &a)const{
        return val<a.val;
    }
}p[MAXN];
void dfs(int x,int f){
    for(int i=1;i<19&&fa[x][i-1];i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
        maxl[x][i]=max(maxl[x][i-1],maxl[fa[x][i-1]][i-1]);
    }
    deep[x]=deep[f]+1;
    for(int i=head[x];i;i=nxt[i]){
        int u=px[i];
        if(u==f)
            continue;
        fa[u][0]=x;
        maxl[u][0]=vax[i];
        dist[u]=dist[x]+vax[i];
        dfs(u,x);
    }
}
int quem(int u,int v){
    if(deep[u]<deep[v])
        swap(u,v);
    int res=0;
    for(int i=18;i>=0;i--)
        if(deep[fa[u][i]]>=deep[v]){
            res=max(res,maxl[u][i]);
            u=fa[u][i];
        }
    if(u==v)
        return res;
    for(int i=18;i>=0;i--)
        if(fa[u][i]!=fa[v][i]){
            res=max(res,maxl[u][i]);
            res=max(res,maxl[v][i]);
            u=fa[u][i];
            v=fa[v][i];
        }
    return max(res,max(maxl[u][0],maxl[v][0]));
}
inline int lca(int u,int v){
    if(deep[u]<deep[v])
        swap(u,v);
    int res=0;
    for(int i=18;i>=0;i--)
        if(deep[fa[u][i]]>=deep[v])
            u=fa[u][i];
    if(u==v)
        return u;
    for(int i=18;i>=0;i--)
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    return fa[u][0];
}
int lower(int x,int y){
    if(deep[x]<deep[y])
        return y;
    return x;
}
pair<int,int> get_inter(int pp2,int pp1,int x,int y,int u,int v){
    int p1=lca(u,x),p2=lca(u,y);
    int p3=lca(v,x),p4=lca(v,y);
    pp1=lower(pp1,pp2);
    int A=lower(p1,p2);
    int B=lower(p3,p4);
    if(deep[A]<deep[pp1]&&deep[B]<deep[pp1])
        return make_pair(-1,-1);
    if(deep[A]<deep[pp1])
        A=pp1;
    if(deep[B]<deep[pp1])
        B=pp1;
    return make_pair(A,B);
}
int main(){
    Read(n),Read(m);
    int u,v,va;
    for(int i=1;i<n;i++){
        Read(u),Read(v),Read(va);
        add_edge(u,v,va);
        add_edge(v,u,va);
    }
    dfs(1,0);
    int maxv=0;
    for(int i=1;i<=m;i++){
        Read(p[i].u),Read(p[i].v);
        p[i].lcax=lca(p[i].u,p[i].v);
        p[i].val=dist[p[i].u]+dist[p[i].v]-(dist[p[i].lcax]<<1);
    }
    sort(p+1,p+1+m);
    maxv=max(maxv,p[m].val);
    pair<int,int> res=make_pair(p[m].u,p[m].v);
    int ans=max(p[m-1].val,maxv-quem(res.first,res.second));
    for(int i=m-1;i>=1;i--){
        res=get_inter(p[i].lcax,lca(res.first,res.second),res.first,res.second,p[i].u,p[i].v);
        if(res.first==res.second)
            break;
        ans=min(ans,max(p[i-1].val,maxv-quem(res.first,res.second)));
        if(maxv-quem(res.first,res.second)>p[i-1].val)
            break;
    }
    PF("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/82628021