洛谷3384树链剖分模板——树链剖分用size域处理子树问题

题目:luogu3384.

不会树剖的点这里.

题目大意:在一棵树上支持:

1.格式1 x y z,表示将x到y的路径上的点权都加上z.

2.格式2 x y,表示查询x到y路径上的点权和.

3.格式3 x z,表示将x的子树节点的点权都加上z.

4.格式4 x,表示查询x的子树的点权和.

注:原题上所有答案对P取模.

这道题其实也很水,但是主要是有一个对子树进行操作的难点.

对子树进行操作的话,我们得先知道,树链剖分剖的时候,一棵子树的节点是在同一个区间内的.

那么左右端点呢?左端点肯定是树根,右端点我们可以通过这棵子树的size域计算出来.

那么这道题其实就是很裸的树链剖分了,代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
struct node{
  int dad,deep,son,size,top,dfn;
  LL v;
}nod[N+9];
struct side{
  int y,next;
}e[N*2+9];
struct tree{
  int l,r;
  LL sum,tag;
}tr[N*5];
int n,m,r,top,t,order[N+9],lin[N+9];
LL mod;
void ins(int X,int Y){
  e[++top].y=Y;
  e[top].next=lin[X];
  lin[X]=top;
}
void dfs1(int k,int father){
  nod[k].size=1;
  nod[k].deep=nod[father].deep+1;
  nod[k].dad=father;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^father) {
      dfs1(e[i].y,k);
      nod[k].size+=nod[e[i].y].size;
      if (nod[e[i].y].size>nod[nod[k].son].size) nod[k].son=e[i].y;
    }
}
void dfs2(int k,int start){
  nod[k].top=start;
  nod[k].dfn=++t;
  order[t]=k;
  if (nod[k].son) dfs2(nod[k].son,start);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^nod[k].dad&&e[i].y^nod[k].son) dfs2(e[i].y,e[i].y);
}
void update(int k,LL num){
  tr[k].tag=(tr[k].tag+num)%mod;
  tr[k].sum=(tr[k].sum+(tr[k].r-tr[k].l+1)*num%mod)%mod;
}
void pushup(int k){
  tr[k].sum=(tr[k<<1].sum+tr[k<<1|1].sum)%mod;
}
void pushdown(int k){
  update(k<<1,tr[k].tag);update(k<<1|1,tr[k].tag);
  tr[k].tag=0LL;
}
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;
  if (L==R){
    tr[k].sum=nod[order[L]].v;
    return;
  }
  int mid=tr[k].l+tr[k].r>>1;
  build(L,mid,k<<1),build(mid+1,R,k<<1|1);
  pushup(k);
}
void add(int L,int R,LL num,int k=1){
  if (L==tr[k].l&&R==tr[k].r){
    update(k,num);
    return;
  }
  pushdown(k);
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) add(L,R,num,k<<1);
  else if (L>mid) add(L,R,num,k<<1|1);
    else add(L,mid,num,k<<1),add(mid+1,R,num,k<<1|1);
  pushup(k);
}
LL query(int L,int R,int k=1){
  if (L==tr[k].l&&R==tr[k].r) return tr[k].sum;
  int mid=tr[k].l+tr[k].r>>1;
  pushdown(k);
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else return (query(L,mid,k<<1)+query(mid+1,R,k<<1|1))%mod;
}
void Add(int u,int v,LL num){
  while (nod[u].top^nod[v].top){
    if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v);
    add(nod[nod[u].top].dfn,nod[u].dfn,num);
    u=nod[nod[u].top].dad;
  }
  if (nod[u].deep>nod[v].deep) swap(u,v);
  add(nod[u].dfn,nod[v].dfn,num);
}
LL Query(int u,int v){
  LL sum=0LL;
  while (nod[u].top^nod[v].top){
    if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v);
    sum=(sum+query(nod[nod[u].top].dfn,nod[u].dfn))%mod;
    u=nod[nod[u].top].dad;
  }
  if (nod[u].deep>nod[v].deep) swap(u,v);
  return (sum+query(nod[u].dfn,nod[v].dfn))%mod;
}
Abigail into(){
  scanf("%d%d%d%lld",&n,&m,&r,&mod);
  for (int i=1;i<=n;i++){
    scanf("%lld",&nod[i].v);
    nod[i].v=(nod[i].v%mod+mod)%mod;
  }
  int x,y;
  for (int i=1;i<n;i++){
    scanf("%d%d",&x,&y);
    ins(x,y);ins(y,x);
  }
}
Abigail work(){
  dfs1(r,0);
  dfs2(r,r);
  build(1,n);
  int x,y,opt;
  LL z;
  for (int i=1;i<=m;i++){
    scanf("%d",&opt);
    switch (opt){
      case 1:scanf("%d%d%lld",&x,&y,&z);
             z=(z%mod+mod)%mod;
             Add(x,y,z);
             break;
      case 2:scanf("%d%d",&x,&y);
             printf("%lld\n",Query(x,y)%mod);
             break;
      case 3:scanf("%d%lld",&x,&z);
             z=(z%mod+mod)%mod;
             add(nod[x].dfn,nod[x].dfn+nod[x].size-1,z);
             break;
      case 4:scanf("%d",&x);
             printf("%lld\n",query(nod[x].dfn,nod[x].dfn+nod[x].size-1)%mod);
             break;
    }
  }
}
Abigail outo(){
}
int main(){
  into();
  work();
  outo();
  return 0;
} 

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/81032288
今日推荐