F Colorful Tree
题意: 给定一棵树,每个树的边除了边权,还有一个颜色,多条边可能有同一种颜色,每次询问将所有颜色为x的边修改为y,询问
u
−
>
v
u->v
u−>v的距离
分析: 树上求距离,离不开
l
c
a
lca
lca,考虑q次修改是相互不影响的,可以离线做,先预处理出lca
然后根据惯例
d
i
s
(
u
,
v
)
=
d
i
s
[
u
]
+
d
i
s
[
v
]
−
2
∗
d
i
s
[
l
c
a
(
u
,
v
)
]
dis(u,v) = dis[u]+dis[v]-2*dis[lca(u,v)]
dis(u,v)=dis[u]+dis[v]−2∗dis[lca(u,v)],怎么处理修改呢,我们可以在
u
,
v
,
l
c
a
(
u
,
v
)
u,v,lca(u,v)
u,v,lca(u,v)这三个点加上标记,然后进行dfs,dfs当前节点的时候我们知道
n
u
m
[
]
,
v
a
l
u
e
[
]
num[],value[]
num[],value[]
n
u
m
[
i
]
num[i]
num[i] 代表从1号点到当前点颜色为i的有多少个,
v
a
l
u
e
[
i
]
value[i]
value[i]代表从1号点到现在节点,颜色
i
i
i的贡献是多少,之后我们就可以更新ans了
const int maxn =3e5+10;
struct Edge{
int to,corlor,w;
};
vector<Edge> G[maxn];
int depth[maxn],vs[maxn],ID[maxn],dis[maxn];
int n;
int f[maxn][20];
void dfs(int node,int fa,int d,int &k){
ID[node] = k;
vs[k] = node;
depth[k++] = d;
// dis[node] = distance;
for(int i = 0;i < G[node].size(); ++i){
Edge &t = G[node][i];
if(t.to == fa) continue;
dis[t.to] = dis[node]+t.w;
dfs(t.to,node,d+1,k);
vs[k] = node;
depth[k++] = d;
}
}
void init_rmq(int n){
for(int i = 1;i <= n ; ++i) f[i][0] = i;
for(int j = 1;(1<<j) <= n; ++j){
for(int i = 1;i + (1<<j)-1 <= n; ++i){
if(depth[f[i][j-1]]< depth[f[i+(1<<(j-1))][j-1]])
f[i][j] = f[i][j-1];
else
f[i][j] = f[i+(1<<(j-1))][j-1];
}
}
}
int rmq_query(int l,int r){
int x = 0;
while((1<<(x+1)) <= r-l+1) x++;
if(depth[f[l][x]] < depth[f[r-(1<<x)+1][x]])
return f[l][x];
else
return f[r-(1<<x)+1][x];
}
void init_lca(){
int k = 1;
dfs(1,-1,0,k);
init_rmq(2*n-1);
}
int lca(int u,int v){
// cout<<rmq_query(ID[u],ID[v])<<endl;
return vs[rmq_query(min(ID[u],ID[v]),max(ID[u],ID[v]))];
}
struct que{
int corlor,w,coe,id;
};
vector<que> Query[maxn];
int ans[maxn],num[maxn],value[maxn];// num[i] 个数,value 值
void dfs(int u,int fa){
for(auto qu:Query[u]){
// cout<<dis[u]<<endl;
ans[qu.id] +=(dis[u]+num[qu.corlor]*qu.w-value[qu.corlor])*qu.coe;
}
for(auto p: G[u]){
int to = p.to;
if(to == fa) continue;
num[p.corlor]++;
value[p.corlor] += p.w;
dfs(to,u);
num[p.corlor]--;
value[p.corlor] -= p.w;
}
}
int main(void)
{
int q;
cin>>n>>q;
for(int i = 1;i < n;++i){
int u,v,c,w;
scanf("%d%d%d%d",&u,&v,&c,&w);
G[u].Pb(Edge{v,c,w});
G[v].Pb(Edge{u,c,w});
}
init_lca();
for(int i = 1;i <= q; ++i){
int x,y,u,v;
scanf("%d%d%d%d",&x,&y,&u,&v);
int fa = lca(u,v);
Query[u].Pb(que{x,y,1,i});
Query[v].Pb(que{x,y,1,i});
Query[fa].Pb(que{x,y,-2,i});
}
dfs(1,-1);
for(int i = 1;i <= q; ++i){
printf("%d\n",ans[i]);
}
return 0;
}