D12 Luogu P3384【模板】轻重链剖分/树链剖分

视频链接:D12 Luogu P3384【模板】轻重链剖分/树链剖分_哔哩哔哩_bilibili

 

 

 

 

Luogu P3384 【模板】轻重链剖分/树链剖分

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

#define LL long long
#define lc u<<1
#define rc u<<1|1
const int N=100010;
int n,m,a,b,root,P,w[N];
vector<int> e[N];
int fa[N],son[N],dep[N],siz[N];
int top[N],id[N],nw[N],tim; //重链
struct tree{
  int l,r; 
  LL add,sum;
}tr[N*4]; //线段树

void dfs1(int u,int f){//搞fa,dep,siz,son
  fa[u]=f,dep[u]=dep[f]+1,siz[u]=1;
  for(int v:e[u]){
    if(v==f) continue;
    dfs1(v,u);
    siz[u]+=siz[v];
    if(siz[son[u]]<siz[v]) son[u]=v; 
  }
}
void dfs2(int u,int tp){ //搞top,id,nw
  top[u]=tp,id[u]=++tim,nw[tim]=w[u];
  if(!son[u]) return;
  dfs2(son[u],tp);
  for(int v:e[u]){
    if(v==fa[u]||v==son[u])continue;
    dfs2(v,v);
  }
}
void pushup(int u){
  tr[u].sum=tr[lc].sum+tr[rc].sum;
}
void pushdown(int u){
  if(tr[u].add){
    tr[lc].sum+=tr[u].add*(tr[lc].r-tr[lc].l+1);
    tr[rc].sum+=tr[u].add*(tr[rc].r-tr[rc].l+1);
    tr[lc].add+=tr[u].add;
    tr[rc].add+=tr[u].add;
    tr[u].add=0;
  }
}
void build(int u,int l,int r){ //构建线段树
  tr[u]={l,r,0,nw[r]};
  if(l==r) return;
  int mid=l+r>>1;
  build(lc,l,mid),build(rc,mid+1,r);
  pushup(u);
}
void change(int u,int l,int r,int k){ //线段树修改
  if(l<=tr[u].l&&tr[u].r<=r){
    tr[u].add+=k;
    tr[u].sum+=k*(tr[u].r-tr[u].l+1);
    return;
  }
  pushdown(u);
  int mid=tr[u].l+tr[u].r>>1;
  if(l<=mid) change(lc,l,r,k);
  if(r>mid) change(rc,l,r,k);
  pushup(u);
}
void change_path(int u,int v,int k){ //修改路径
  while(top[u]!=top[v]){
    if(dep[top[u]]<dep[top[v]]) swap(u,v);
    change(1,id[top[u]],id[u],k);
    u=fa[top[u]];
  }
  if(dep[u]<dep[v]) swap(u,v);
  change(1,id[v],id[u],k); //最后一段
}
void change_tree(int u,int k){ //修改子树
  change(1,id[u],id[u]+siz[u]-1,k);
}
LL query(int u,int l,int r){ //线段树查询
  if(l<=tr[u].l&&tr[u].r<=r)return tr[u].sum;
  pushdown(u);
  int mid=tr[u].l+tr[u].r>>1;
  LL res=0;
  if(l<=mid) res+=query(lc,l,r);
  if(r>mid) res+=query(rc,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;
}
LL query_tree(int u){ //查询子树
  return query(1,id[u],id[u]+siz[u]-1);
}
int main(){
  scanf("%d%d%d%d",&n,&m,&root,&P);
  for(int i=1; i<=n; i++) scanf("%d",&w[i]);
  for(int i=0; i<n-1; i++){
    scanf("%d%d",&a,&b);
    e[a].push_back(b); e[b].push_back(a);
  }
  dfs1(root,0);
  dfs2(root,root); //把树拆成链
  build(1,1,n);  //用链建线段树
  while(m--){
    int t,u,v,k; scanf("%d%d",&t,&u);
    if(t==1){
      scanf("%d%d",&v,&k);
      change_path(u,v,k);
    }
    else if(t==3){
      scanf("%d",&k);
      change_tree(u,k);
    }
    else if(t==2){
      scanf("%d",&v);
      printf("%d\n",query_path(u,v)%P);
    }
    else printf("%d\n",query_tree(u)%P);
  }
}

 

练习:

Luogu P2486 [SDOI2011] 染色

Luogu P4211 [LNOI2014] LCA

Luogu P3313 [SDOI2014] 旅行

Luogu P4219 [BJOI2014] 大融合

Luogu P4216 [SCOI2015] 情报传递

Luogu P2146 [NOI2015] 软件包管理器

Luogu P5305 [GXOI/GZOI2019] 旧词

Luogu P1505 [国家集训队] 旅游

 

posted @ 2022-05-28 13:26  董晓  阅读(837)  评论(1编辑  收藏  举报