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\n",max(qdis(x,v),qdis(y,v)));
        }
    }
    return 0;
}
View Code

 

posted @ 2019-09-20 16:35  StarHai  阅读(790)  评论(0编辑  收藏  举报