ABC294G Distance Queries on a Tree

唯一会的 G

AtCoder 链接

洛谷链接

  • \(n\) 个点的树,\(Q\) 次操作:

    • \(\texttt{1 }i\texttt{ }w\),将第 \(i\) 条边边权改为 \(w\)

    • \(\texttt{2 }x\texttt{ }y\),查询 \(x,y\) 之间路径的权值和。

  • \(n,Q\le 2\times 10^5\)

树剖板子,运用边转点技巧,由于只有单点修改,套上树状数组维护即可。

详见我的树链剖分讲解博客

简单来说,我们先随便从一个点开始 DFS,将边权转化为其深度较大的节点的权值,然后就变成了对点的操作了。

时间复杂度为 \(\mathcal{O}(Q\log^2 n)\),空间复杂度为 \(\mathcal{O}(n)\)

评测记录

$\bf\color{orange}点击查看代码$
#include<bits/stdc++.h>
#define N 200005
#define int long long
using namespace std;
int n,q,f[N],h[N],t[N],sz[N],dfn[N],to[N],d[N],bit[N],val[N];
struct edge{
    int v,w,id;
};
vector<edge>g[N];
void modify(int x,int k){
    for(int i=x;i<=n;i+=i&(-i)){
        bit[i]+=k;
    }
}
int query(int x){
    int ret=0;
    for(int i=x;i;i-=i&(-i)){
        ret+=bit[i];
    }
    return ret;
}
void dfs1(int u,int fa){
    sz[u]=1;
    for(auto[v,w,id]:g[u]){
        if(v^fa){
            f[v]=u;
            to[id]=v;
            val[v]=w;
            d[v]=d[u]+1;
            dfs1(v,u);
            sz[u]+=sz[v];
        }        
    }
}
void dfs2(int u,int fa){
    for(auto[v,w,id]:g[u]){
        if(v^fa){
            if((sz[v]<<1)>sz[u]){
                t[v]=t[u];
                h[u]=v;
            }else{
                t[v]=v;
            }
            dfs2(v,u);
        }
    }
}
void dfs3(int u,int fa){
    ++dfn[0];
    dfn[u]=dfn[0];
    modify(dfn[u],val[u]);
    if(h[u]){
        dfs3(h[u],u);
    }
    for(auto[v,w,id]:g[u]){
        if((v^fa)&&(v^h[u])){
            dfs3(v,u);
        }
    }
}
int pathquery(int x,int y){
    int ret=0;
    while(t[x]^t[y]){
        if(d[t[x]]<d[t[y]]){
            swap(x,y);
        }
        ret+=query(dfn[x])-query(dfn[t[x]]-1);
        x=f[t[x]];
    }
    if(x^y){
        if(d[x]>d[y]){
            swap(x,y);
        }
        ret+=query(dfn[y])-query(dfn[x]);
    }
    return ret;
}
signed main(){
    scanf("%lld",&n);
    for(int i=1,u,v,w;i^n;++i){
        scanf("%lld%lld%lld",&u,&v,&w);
        g[u].push_back({v,w,i});
        g[v].push_back({u,w,i});
    }
    dfs1(1,0);
    t[1]=1;
    dfs2(1,0);
    dfs3(1,0);
    scanf("%lld",&q);
    for(int op,x,y;q--;){
        scanf("%lld%lld%lld",&op,&x,&y);
        if(op==1){
            modify(dfn[to[x]],-val[to[x]]);//修改相当于减去原值再加上新值。
            modify(dfn[to[x]],y);
            val[to[x]]=y;
        }else{
            printf("%lld\n",pathquery(x,y));
        }
    }
}
posted @ 2023-05-31 21:27  lzyqwq  阅读(20)  评论(0)    收藏  举报