• 2019 ICPC上海网络赛 A 题 Lightning Routing I (动态维护树的直径)


    题目:

    给定一棵树, 带边权。

    现在有2种操作:

    1.修改第i条边的权值。

    2.询问u到其他一个任意点的最大距离是多少。

    题解:

    树的直径可以通过两次 dfs() 的方法求得。换句话说,到任意点最远的点,一定是直径的某个端点(反证法)。

    • 因此原问题转化为动态维护直径,然后再支持询问两个点的距离,后者可以 dfs 序 + lca + 树状数组。

    参考代码:

    #include<bits/stdc++.h>
    #define lowbit(x) (x&-x)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define mkp make_pair
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int mod=998244353;
    const int INF=1<<30;
    const int maxn=1e5+10;
    struct Edge{
        int u,v,w;
    } eg[maxn];
    vector<pii> edge[maxn];
    int n,q,tin[maxn],tout[maxn],rid[maxn],tot;
    
    namespace hld{
        //树状数组 
        struct BIT{
            ll a[maxn];
            inline void update(int i,int x) 
            {
                while(i<=n) 
                    a[i]+=x,i+=lowbit(i);
            }
            inline void update(int l,int r,int x) 
            {
                update(l,x); update(r+1,-x);
            }
            inline ll query(int i) 
            {
                ll res=0;
                while(i) res+=a[i],i-=lowbit(i);
                return res;
            }
        } bit;
        //树链剖分 
        int siz[maxn],dep[maxn],fa[maxn],son[maxn],top[maxn];
        void dfs(int u,int f) 
        {
            tin[u]=++tot; rid[tot]=u;
            dep[u]=dep[f]+1; fa[u]=f; siz[u]=1; son[u]=0;
            int m=-1;
            for(auto&x:edge[u]) 
            {
                int v=x.first;
                if(v==f) continue;
                dfs(v,u);
                bit.update(tin[v],tout[v],x.second);//节点到根的距离 
                siz[u]+=siz[v];
                if(siz[v]>m) son[u]=v,m=siz[v];
            }
            tout[u]=tot;
        }
        void dfs(int u,int f,int tp) 
        {
            top[u]=tp;
            if(!son[u]) return;
            dfs(son[u],u,tp); 
            for(auto&x:edge[u]) 
            {
                int v=x.first;
                if(v==f||v==son[u]) continue;
                dfs(v,u,v);
            }
        }
        void build() //树链剖分 
        {
            dfs(1,0);dfs(1,0,1);
        }
        int qlca(int u,int v) 
        {
            while(top[u]!=top[v])
            {
                if(dep[top[u]]<dep[top[v]]) swap(u,v);
                u=fa[top[u]];
            }
            return dep[u]<dep[v]?u:v;
        }
        ll qdis(int u,int v) 
        {
            ll r=bit.query(tin[u])+bit.query(tin[v]);
            int l=qlca(u,v);
            return r-2ll*bit.query(tin[l]);
        }
    }
    using hld::qdis;
    //线段树+树状数组动态维护树直径 
    struct Node{
        int u,v; 
        ll d;
    } tr[maxn<<2];
    void pushup(int rt) 
    {
        tr[rt]=tr[rt<<1].d>tr[rt<<1|1].d ? tr[rt<<1]:tr[rt<<1|1];
        int x=tr[rt<<1].u,y=tr[rt<<1].v;
        int u=tr[rt<<1|1].u,v=tr[rt<<1|1].v;
        ll tot;
        if((tot=qdis(x,u))>tr[rt].d) tr[rt]=(Node){x,u,tot};
        if((tot=qdis(x,v))>tr[rt].d) tr[rt]=(Node){x,v,tot};
        if((tot=qdis(y,u))>tr[rt].d) tr[rt]=(Node){y,u,tot};
        if((tot=qdis(y,v))>tr[rt].d) tr[rt]=(Node){y,v,tot};
    }
    void build(int l,int r,int rt) 
    {
        if(l==r) 
        {
            int u=rid[l];
            tr[rt]=(Node){u,u,0};
            return ;
        }
        int m=(l+r)/2;
        build(lson); build(rson);
        pushup(rt);
    }
    void update(int L,int R,int l,int r,int rt) 
    {
        if(L<=l && r<=R) return ;
        int m=(l+r)/2;
        if(L<=m) update(L,R,lson);
        if(R>m) update(L,R,rson);
        pushup(rt);
    }
    
    int main() 
    {
        scanf("%d",&n);
        for(int i=1;i<n;i++) 
        {
            scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].w);
            edge[eg[i].u].push_back({eg[i].v,eg[i].w});
            edge[eg[i].v].push_back({eg[i].u,eg[i].w});
        }
        hld::build(); //树链剖分 
        build(1,n,1);
        
        scanf("%d",&q);
        char op[2];
        int e,v,w; 
        for(int i=1;i<=q;++i) 
        {
            scanf("%s",op);
            if(op[0]=='C') 
            {
                scanf("%d%d",&e,&w);
                int u=eg[e].u,v=eg[e].v,ww=eg[e].w;
                if(hld::fa[v]!=u) swap(u,v);
                hld::bit.update(tin[v],tout[v],w-ww);
                eg[e].w=w;
                update(tin[v],tout[v],1,n,1);
            } 
            else if(op[0]=='Q') 
            {
                scanf("%d",&v);
                int x=tr[1].u,y=tr[1].v;
                printf("%lld
    ",max(qdis(x,v),qdis(y,v)));
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    WinForm中AssemblyInfo.cs文件参数具体讲解
    ISO18000-6B和ISO18000-6C(EPC C1G2)标准的区别
    Win8.1下VM与Hyper-v冲突解决方法
    Mifare l卡特性简介
    【Python爬虫】beautifulsoup4库的安装与调用
    【Python爬虫】已知jpg文件url-下载图片
    【Python爬虫】测试
    【Python爬虫】Requests库的安装
    【Python】以模块化做比赛模拟
    【真随笔】未来出路,在哪里?
  • 原文地址:https://www.cnblogs.com/csushl/p/11558054.html
Copyright © 2020-2023  润新知