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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章