ABC133F Colorful Tree
给出 \(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;
}

浙公网安备 33010602011771号