树链剖分+线段树维护板子
时间复杂度O(mlogn*logn)
用于解决u-v最短路径权值问题
解决u子树点权值和问题
可以将两点之间深度较深的那一个点的权值映射到这条边的权值
从而通过维护点权值间接维护边权值
每次只需要lca那一点的权值不动即可
int w[maxn];
vector<int>e[maxn];
int fa[maxn],dep[maxn],sz[maxn],son[maxn];
//每个节点的父亲,深度,以u为根的树大小,重儿子
int top[maxn],id[maxn],nw[maxn],cnt;
//存u所在重链的顶点,u剖分后的新编号,新编号在树中所对应节点的权值
void dfs1(int u,int father){
fa[u]=father;dep[u]=dep[father]+1;sz[u]=1;
for(int v:e[u]){
if(v==father)continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v])son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t,id[u]=++cnt,nw[cnt]=w[u];
if(!son[u])return;
dfs2(son[u],t);
for(int v:e[u]){
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);//轻儿子
}
}
struct node{
int l,r;
ll sum,add;
}tr[4*maxn];
void pushup(int u){
tr[u].sum=tr[2*u].sum+tr[2*u+1].sum;
}
void pushdown(int p){
if(tr[p].add){
int debt=tr[p].add;
tr[2*p].sum+=debt*(tr[2*p].r-tr[2*p].l+1);
tr[2*p+1].sum+=debt*(tr[2*p+1].r-tr[2*p+1].l+1);
tr[2*p].add+=debt;
tr[2*p+1].add+=debt;
tr[p].add=0;
}
}
void build(int p,int l,int r){
tr[p]=node{l,r,nw[l],0};
if(l==r)return;
int m=l+r>>1;
build(2*p,l,m);build(2*p+1,m+1,r);
pushup(p);
}
//查询:求树从x到y节点最短路径上所有节点的值之和
ll query(int u,int l,int r){//线段树
if(l<=tr[u].l&&tr[u].r<=r)return tr[u].sum;
pushdown(u);
int m=tr[u].l+tr[u].r>>1;
ll res=0;
if(l<=m)res+=query(2*u,l,r);
if(r>m)res+=query(2*u+1,l,r);
return res;
}
ll query_path(int u,int v){//原树
ll res=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
res+=query(1,id[top[u]],id[u]);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
res+=query(1,id[v],id[u]);
return res;
}
//修改:将树从x到y节点最短路径所有节点加上k
void update(int u,int l,int r,int k){//线段树
if(l<=tr[u].l&&r>=tr[u].r){
tr[u].add+=k;
tr[u].sum+=k*(tr[u].r-tr[u].l+1);
return;
}
pushdown(u);
int m=tr[u].l+tr[u].r>>1;
if(l<=m)update(2*u,l,r,k);
if(r>m)update(2*u+1,l,r,k);
pushup(u);
}
void update_path(int u,int v,int k){//原树
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
update(1,id[top[u]],id[u],k);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
update(1,id[v],id[u],k);
}
//修改/查询:树上以u为根的子树的点权和
void update_tree(int u,int k){//线段树
update(1,id[u],id[u]+sz[u]-1,k);
}
ll query_tree(int u){//原树
return query(1,id[u],id[u]+sz[u]-1);
}
void solve(){
int n,m,r,p;cin>>n>>m>>r>>p;
for(int i=1;i<=n;i++){
cin>>w[i];
}
for(int i=1;i<=n-1;i++){
int u,v;cin>>u>>v;
e[u].pb(v);
e[v].pb(u);
}
dfs1(r,0);
dfs2(r,r);
build(1,1,n);
for(int i=1;i<=m;i++){
int opt;cin>>opt;
int x,y,z;
if(opt==1){
cin>>x>>y>>z;
update_path(x,y,z);
}else if(opt==2){
cin>>x>>y;
cout<<query_path(x,y)%p<<endl;
}else if(opt==3){
cin>>x>>z;
update_tree(x,z);
}else{
cin>>x;
cout<<query_tree(x)%p<<endl;
}
}
}

浙公网安备 33010602011771号