ABC133F Colorful Tree

洛谷链接

AtCoder 链接

  • 给出 \(N\) 个节点的树,每条边有颜色、边权。处理 \(Q\) 个询问,第 \(i\) 次询问给出 \(x_i,y_i,u_i,v_i\),表示先将所有颜色为 \(x_i\) 的边边权变成 \(y_i\),再求出 \(u_i\)\(v_i\) 的路径边权和。询问之间相互独立,即不会真的修改

  • \(N,Q\le 10^5\)

首先,路径上的边修改后才会影响答案。考虑树剖,先边转点。使用动态开点技巧在树剖后的序列上对每种颜色维护线段树,记录当前区间内有效边的个数 \(tot\) 以及有效边的边权和 \(sum\)。同时维护前缀和。

跳链时,先用前缀和查询原边权和,再在线段树上查询该区间的信息,记查询到的和为 \(a\),个数为 \(b\)。则要\(a\) 那一部分的贡献换成 \(b\times y_i\),对应的答案加上 \(b\times y_i-a\)。特判颜色不存在的情况。

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

评测记录

$\color{orange}\bf 点击查看代码$
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,f[N],sz[N],d[N],val[N],col[N],dfn[N],id,h[N],t[N],qzh[N],rt[N],sum[N*20],tot[N*20],cnt,ls[N*20],rs[N*20];
struct edge{
    int v,c,w;
};
vector<edge>g[N];
void insert(int&x,int l,int r,int k,int v){
    if(!x){
        ++cnt;
        x=cnt;
    }
    sum[x]+=v;
    ++tot[x];
    if(l^r){
        int mid=(l+r)>>1;
        if(k<=mid){
            insert(ls[x],l,mid,k,v);
        }else{
            insert(rs[x],mid+1,r,k,v);
        }
    }
}
pair<int,int>query(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return make_pair(sum[x],tot[x]);
    }
    int mid=(l+r)>>1,fi=0,se=0;
    if(ql<=mid&&ls[x]){
        auto[a,b]=query(ls[x],l,mid,ql,qr);
        fi+=a;
        se+=b;
    }
    if(qr>mid&&rs[x]){
        auto[a,b]=query(rs[x],mid+1,r,ql,qr);
        fi+=a;
        se+=b;
    }
    return make_pair(fi,se);
}
void dfs1(int u,int fa){
    sz[u]=1;
    for(auto[v,c,w]:g[u]){
        if(v^fa){
            d[v]=d[u]+1;
            f[v]=u;
            val[v]=w;
            col[v]=c;
            dfs1(v,u);
            sz[u]+=sz[v];
        }
    }
}
void dfs2(int u,int fa){
    for(auto[v,c,w]:g[u]){
        if(v^fa){
            if((sz[v]<<1)>sz[u]){
                h[u]=v;
                t[v]=t[u];
            }else{
                t[v]=v;
            }
            dfs2(v,u);
        }
    }
}
void dfs3(int u,int fa){
    ++id;
    dfn[u]=id;
    qzh[id]=qzh[id-1]+val[u];
    insert(rt[col[u]],1,n,id,val[u]);
    if(h[u]){
        dfs3(h[u],u);
    }
    for(auto[v,c,w]:g[u]){
        if((v^h[u])&&(v^fa)){
            dfs3(v,u);
        }
    }
}
void pathquery(int x,int y,int u,int v){
    int ans=0;
    while(t[u]^t[v]){
        if(d[t[u]]<d[t[v]]){
            swap(u,v);
        }
        ans+=qzh[dfn[u]]-qzh[dfn[t[u]]-1];
        if(rt[x]){
            auto[a,b]=query(rt[x],1,n,dfn[t[u]],dfn[u]);
            ans+=b*y-a;
        }
        u=f[t[u]];
    }
    if(u^v){
        if(d[u]>d[v]){
            swap(u,v);
        }
        ans+=qzh[dfn[v]]-qzh[dfn[u]];
        if(rt[x]){
            auto[a,b]=query(rt[x],1,n,dfn[u]+1,dfn[v]);
            ans+=b*y-a;
        }
    }
    printf("%d\n",ans);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,u,v,c,d;i^n;++i){
        scanf("%d%d%d%d",&u,&v,&c,&d);
        g[u].emplace_back(edge{v,c,d});
        g[v].emplace_back(edge{u,c,d});
    }
    dfs1(1,0);
    t[1]=1;
    dfs2(1,0);
    dfs3(1,0);
    for(int i=1,x,y,u,v;i<=m;++i){
        scanf("%d%d%d%d",&x,&y,&u,&v);
        pathquery(x,y,u,v);
    }
    return 0;
}
posted @ 2023-06-16 10:38  lzyqwq  阅读(18)  评论(0)    收藏  举报