P3384 模板树链剖分

Posted cherish-lin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3384 模板树链剖分相关的知识,希望对你有一定的参考价值。

#include<bits/stdc++.h>
// #include<iostream>
// #include<stdio.h>
// #include<iomanip>
// #include<stack>
// #include<queue>
// #include<algorithm>
// #include<cstring>
// #include<map>
// #include<vector>
// #include<numeric>
// #include<iterator>
// #include<cmath>
#define met(a,x) memset(a,x,sizeof(a));
#define lowbit(x) (x&(-x))
#define mid ((l + r) >> 1)
#define len (r - l + 1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
int lcm(int a, int b) { return a * b / gcd(a, b); }
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>Pi;
typedef pair<ll, ll>Pii;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1);
map<int,int>mp;
map<int, char *>mp1;
map<char *, int>mp2;
map<char, int>mp3;
map<string,int>mp4;
map<char,int>mp5;
const int maxn = 400010;
// const int mod=1000000007;
ll a[maxn];
int dep[maxn],f[maxn],rev[maxn],id[maxn];
int siz[maxn],son[maxn],top[maxn],head[maxn];
int val[maxn],sum[maxn],lazy[maxn];
int cnt,tot,n,m,r,mod;

int read(){
    int flag=1;
    int sum=0;
    char c=getchar();
    while(c<0||c>9){
        if(c==-)flag=-1;
        c=getchar();
    }
    while(c>=0&&c<=9){
        sum=sum*10+c-0;
        c=getchar();
    }
    return sum*flag;
}
ll Read(){
    int flag=1;
    ll sum=0;
    char c=getchar();
    while(c<0||c>9){
        if(c==-)flag=-1;
        c=getchar();
    }
    while(c>=0&&c<=9){
        sum=sum*10+c-0;
        c=getchar();
    }
    return sum*flag;
}
ll quickmul(ll a,ll b){
    ll ans=0;
    while(b){
        if(b&1){
            ans=(ans+a)%mod;
        }
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}
ll quickpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1)
            ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
struct Edge{
  int v,next;
}e[maxn<<1];
void add(int u,int v){
  e[tot] = (Edge){v,head[u]};
  head[u] = tot++;
}
void dfs1(int u,int fa,int d){
  f[u] = fa;
  dep[u] = d;
  siz[u] = 1;
  for(int i = head[u];i != -1;i=e[i].next){
    int v = e[i].v;
    if(v == fa)continue;
    dfs1(v,u,d+1);
    siz[u] += siz[v];
    if(siz[v] > siz[son[u]]){
      son[u] = v;
    }
  }
}
void dfs2(int u,int t){
  top[u] = t;
  id[u] = ++cnt;
  rev[cnt] = u;
  if(!son[u])return ;
  dfs2(son[u],t);
  for(int i = head[u];i != -1;i = e[i].next){
    int v = e[i].v;
    if(v != son[u] && v != f[u]){
      dfs2(v,v);
    }
  }
}
int LCA(int u,int v){// 用于求LCA
  while(top[u] != top[v]){
    if(dep[top[u]] < dep[top[v]]){ // 优先跳深度深的
      swap(u,v);
    }
    u = f[top[u]];
  }
  if(dep[u] < dep[v]) return u;
  return v;
}

void pushup(int rt){
  sum[rt] = (sum[rt<<1] + sum[rt<<1|1]) % mod;
}
void pushdown(int rt,int lenn){
  if(lazy[rt]){
    lazy[rt<<1] += lazy[rt];
    lazy[rt<<1|1] += lazy[rt];
    sum[rt<<1] += lazy[rt] * (lenn - (lenn >> 1));
    sum[rt<<1|1] += lazy[rt] * (lenn >> 1);
    sum[rt] %= mod;
    sum[rt<<1|1] %= mod;
    lazy[rt] = 0;
  }
}
void build(int l,int r,int rt){
  if(l == r){
    lazy[rt] = 0;
    sum[rt] = val[rev[l]];
    sum[rt] %= mod;
    return ;
  }
  build(lson);
  build(rson);
  pushup(rt);
}

void update(int L,int R,int w,int l,int r,int rt){
  if(L <= l && R >= r){
    lazy[rt] += w;
    sum[rt] += w * len;
    sum[rt] %= mod;
    return ;
  }
  pushdown(rt,len);
  if(L <= mid)update(L,R,w,lson);
  if(R >= mid + 1)update(L,R,w,rson);
  pushup(rt);
}
int querysum(int L,int R,int l,int r,int rt){
  if(L <= l && R >= r)return sum[rt];
  int ans=0;
  pushdown(rt,len);
  if(L <= mid)ans += querysum(L,R,lson);
  ans %= mod;
  if(R >= mid + 1)ans += querysum(L,R,rson);
  ans %= mod;
  return ans;
}
void update_Range(int x,int y,int z){
  while(top[x] != top[y]){
    if(dep[top[x]] < dep[top[y]]) swap(x,y);
    update(id[top[x]],id[x],z,1,n,1);
    x = f[top[x]];
  }
  if(dep[x] > dep[y])swap(x,y);
  update(id[x],id[y],z,1,n,1);
}

void update_root(int x,int w){
  update(id[x],id[x] + siz[x] - 1,w,1,n,1);
}

int sum_Range(int x,int y){
  int ans = 0;
  while(top[x] != top[y]){
    if(dep[top[x]] < dep[top[y]])swap(x,y);
    ans += querysum(id[top[x]],id[x],1,n,1);
    ans %= mod;
    x = f[top[x]];
  }
  if(dep[x] > dep[y])swap(x,y);
  ans += querysum(id[x],id[y],1,n,1);
  ans %= mod;
  return ans;
}
int sum_root(int x){
  return querysum(id[x],id[x] + siz[x] - 1,1,n,1);
}

int main()
{
  n = read(),m = read(),r = read(),mod = read();
  for(int i = 1;i <= n;i++)head[i] = -1;
  for(int i = 1;i <= n;i++)val[i] = read();
  for(int i = 1;i <= n - 1;i++){
    int u = read();
    int v = read();
    add(u,v);
    add(v,u);
  }
  dfs1(r,-1,1);
  dfs2(r,r);
  build(1,n,1);
  while(m--){
    int op,x,y,z;
    op = read();
    if(op == 1){
      x = read(),y = read(),z = read();
      z %= mod;
      update_Range(x,y,z);
    }
    else if(op == 2){
      x = read(),y = read();
      int ans = sum_Range(x,y);
      cout << ans << endl;
    }
    else if(op == 3){
      x = read(),z = read();
      z %= mod;
      update_root(x,z);
    }
    else {
      x = read();
      int ans = sum_root(x);
      cout << ans << endl;
    }
  }
  return 0;
}

 

以上是关于P3384 模板树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

P3384 模板树链剖分

P3384 模板树链剖分

P3384 模板树链剖分

Luogu P3384树链剖分模板

洛谷 P3384 模板树链剖分

Luogu P3384 模板树链剖分