牛客挑战赛45-D题[坐标]

坐标

https://ac.nowcoder.com/acm/contest/8563/D

先将T2的贡献计算出来,然后在T1的对应节点上挂一条边权为dep[i]的边.那么题目就变成了求整棵树的直径.用两遍dfs得出直径的两个端点,然后就得出答案.因为是随机数据,每次暴力更新的点不会很多,暴力更新维护一下端点就行.

下面是官方题解,但是没有代码,加了有注释的代码
图片说明

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll
const int maxn = 2e5+20;
int n,q,tot;
struct node{
    int v,val;
};
vector<node>e1[maxn],e2[maxn];
int f2[maxn],dep2[maxn];
//dfs1 获取T2的dep2
void dfs1(int u,int fa)
{
    f2[u]=fa;
    for(auto &t:e2[u]){
        if(t.v==fa)continue;
        dep2[t.v]=dep2[u]+t.val;
        dfs1(t.v,u);
    }
}
int f1[maxn],siz[maxn],deep[maxn],son[maxn];
int dep1[maxn];
void dfs2(int u,int fa)
{
    f1[u]=fa;siz[u]=1;deep[u]=deep[fa]+1;
    for(auto &t:e1[u]){
        if(t.v==fa)continue;
        dep1[t.v]=dep1[u]+t.val;
        dfs2(t.v,u);
        siz[u]+=siz[t.v];
        if(!son[u]||siz[t.v]>siz[son[u]])son[u]=t.v;
    }
}
int top[maxn];
void dfs3(int u,int topf)
{
    top[u]=topf;
    if(!son[u])return ;
    dfs3(son[u],topf);
    for(auto &t:e1[u]){
        if(t.v==son[u]||t.v==f1[u])continue;
        dfs3(t.v,t.v);
    }
}
bool vis[maxn];
ll dtree,now,S,E,D;
void dfs4(int u,int dval)
{
    // cout<<u<<' '<<dval;
    vis[u]=true;
    if(dval>dtree)dtree=dval,now=u;
    for(auto &t:e1[u]){
        if(vis[t.v])continue;
        dfs4(t.v,dval+t.val);
    }
}

int lca(int u,int v)
{
    while(top[u]^top[v]){
        if(deep[top[u]]<=deep[top[v]])swap(u,v);
        u=f1[top[u]];
    }
    return deep[u]<deep[v]?u:v;
}

ll dis(int u,int v){
    return dep1[u]+dep1[v]-2*dep1[lca(u,v)];
}
ll w;
void dfs5(int u,int fa)
//暴力询问当更新当前u点时有没有更改原来的S和E
{
    dep1[u+n]+=w;
    ll D1=dis(u+n,S),D2=dis(u+n,E);
    ll D=max(D1,D2);
    if(D1>D2)now=S;else now=E;
    if(D>dtree)dtree=D,S=now,E=n+u;
    for(auto &t:e2[u]){
        if(t.v==fa)continue;
        dfs5(t.v,u);
    }
}

signed main()
{
    cin>>n>>q;
    for(int i=1;i<n;i++){
        int u,v,w;cin>>u>>v>>w;
        // cout<<u<<v<<w<<endl;
        e1[u].push_back({v,w});
        e1[v].push_back({u,w});
    }
    for(int i=1;i<n;i++){
        int u,v,w;cin>>u>>v>>w;
        e2[u].push_back({v,w});
        e2[v].push_back({u,w});
    }
    dfs1(1,0);
    //在得到T2的dep之后给T1加一条边
    for(int i=1;i<=n;i++){
        e1[i].push_back({i+n,dep2[i]});
        e1[i+n].push_back({i,dep2[i]});
    }
    //T1树链剖分
    dfs2(1,0);
    dfs3(1,1);
    //dfs两遍求树的直径
    dfs4(1,0);S=now;
    dtree=0;memset(vis,0,sizeof vis);
    dfs4(S,0);E=now;

    cout<<dtree<<endl;
    for(int i=1;i<=q;i++){
        int u;cin>>u>>w;
        //暴力更新
        dfs5(u,f2[u]);
        cout<<dtree<<endl;
    }
    return 0;
}
全部评论

相关推荐

11-13 20:32
门头沟学院 Java
面向未来编程code:我没看到他咋急,他不就问你个问题。。。
点赞 评论 收藏
分享
5 收藏 评论
分享
牛客网
牛客企业服务