树链剖分(模板)

Description
这是一道模板题。

给定一棵 n个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值。下面依次进行 m 个操作,操作分为如下五种类型:

  • 换根:将一个指定的节点设置为树的新根。
  • 修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值。
  • 修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值。
  • 询问路径:询问某条路径上节点的权值和。
  • 询问子树:询问某个子树内节点的权值和
Input

第一行为一个整数 n,表示节点的个数。
第二行 n 个整数表示第 i个节点的初始权值 ai​。
第三行 n−1 个整数,表示 i+1 号节点的父节点编号fi+1(1⩽fi+1⩽n)。
第四行一个整数 m,表示操作个数。
接下来 m 行,每行第一个整数表示操作类型编号:(1⩽u,v⩽n)

  • 若类型为 1,则接下来一个整数 u,表示新根的编号。
  • 若类型为 2,则接下来三个整数 u,v,k,分别表示路径两端的节点编号以及增加的权值。
  • 若类型为 3,则接下来两个整数 u,k,分别表示子树根节点编号以及增加的权值。
  • 若类型为 4,则接下来两个整数 u,v,表示路径两端的节点编号。
  • 若类型为 5,则接下来一个整数 u,表示子树根节点编号。
Output

对于每一个类型为 4或 5 的操作,输出一行一个整数表示答案。

  • Sample Input
  • 6
    1 2 3 4 5 6
    1 2 1 4 4
    6
    4 5 6
    2 2 4 1
    5 1
    1 4
    3 1 2
    4 2 5
  • Sample Output
  • 15
    24
    19

#include<bits/stdc++.h>
#define ls ( u << 1 )
#define rs ( ( u <<1 ) | 1 )
#define mid ( ( l + r ) >> 1 )
#define int long long
#define N 100005
 
using namespace std;
 
signed n, a[N], m, x;
signed idx[N], u, v, w;
int tree[N<<2], add[N<<2];
signed adj[N], nextone[N<<1];
signed to[N<<1], cnt, rightson;
signed son[N], size[N];
signed deep[N], fath[N];
signed pos[N], out[N];
signed top[N], tot;
 
inline void addedge( int u, int v )
{
    nextone[++cnt] = adj[u];
    adj[u] = cnt;
    to[cnt] = v;
}
 
inline void pushup( int u )
{
    tree[u] = tree[ls] + tree[rs];
}
 
inline void pushdown( int u, int l, int r )
{
    if( !add[u] ) return;
    add[ls] += add[u];
    add[rs] += add[u];
    tree[ls] += 1ll * ( mid - l + 1 ) * add[u];
    tree[rs] += 1ll * ( r - mid ) * add[u];
    add[u] = 0;
}
 
void build( int u, int l, int r )
{
    if( l == r )
    {
        tree[u] = a[idx[l]];
        return;
    }
     
    build( ls, l, mid );
    build( rs, mid + 1, r );
     
    pushup(u);
}
 
 
void update( int u, int l, int r, int st, int des, int k )
{
    if( st <= l && r <= des )
    {
        add[u] += k;
        tree[u] += 1ll * ( r - l + 1 ) * k;
        return;
    }
     
    pushdown( u, l, r );
     
    if( st <= mid )
    {
        update( ls, l, mid, st, des, k );
    }
     
    if( mid < des )
    {
        update( rs, mid + 1, r, st, des, k );
    }
     
    pushup(u);
}
 
int query( int u, int l, int r, int st, int des )
{
    if( st <= l && r <= des )
    {
        return tree[u];
    }
     
    pushdown( u, l, r );
    int res = 0;
     
    if( st <= mid )
    {
        res += query( ls, l, mid, st, des );
    }
     
    if( mid < des )
    {
        res += query( rs, mid + 1, r, st, des );
    }
     
    pushup(u);
     
    return res;
}
 
void dfs1( int u )
{
    size[u] = 1;
     
    for( int i = adj[u]; i; i = nextone[i] )
    {
        int v = to[i];
         
        if( v == fath[u] )
        {
            continue;
        }
         
        fath[v] = u;
        deep[v] = deep[u] + 1;
        dfs1(v);
        size[u] += size[v];
         
        if( size[v] > size[son[u]] )
        {
            son[u] = v;
        }
    }
}
 
void dfs2( int u, int tp )
{
    pos[u] = ++tot;
    idx[tot] = u;
    top[u] = tp;
     
    if( !son[u] )
    {
        return void( out[u] = tot );
    }
     
    dfs2( son[u], tp );
     
    for( int i = adj[u]; i; i = nextone[i] )
    {
        if( to[i] == fath[u] || to[i] == son[u] )
        {
            continue;
        }
         
        dfs2( to[i], to[i] );
    }
     
    out[u] = tot;
}
 
int lca( int u, int v )
{
    while( top[u] != top[v] )
    {
        if( deep[top[u]] < deep[top[v]] )
        {
            swap(u,v);
        }
         
        u = fath[top[u]];
    }
     
    return deep[u] > deep[v] ? v : u;
}
 
int find( int u, int v )
{
    while( top[u] != top[v] )
    {
        if( deep[top[u]] < deep[top[v]] )
        {
            swap(u,v);
        }
         
        if( fath[top[u]] == v )
        {
            return top[u];
        }
         
        u = fath[top[u]];
    }
     
    if( deep[u] < deep[v] )
    {
        swap( u, v );
    }
     
    return son[v];
}
 
void update2( int u, int v, int k )
{
    while( top[u] != top[v] )
    {
        if( deep[top[u]] < deep[top[v]] )
        {
            swap( u, v );
        }
         
        update( 1, 1, n, pos[top[u]], pos[u], k );
        u = fath[top[u]];
    }
     
    if( deep[u] < deep[v] )
    {
        swap( u, v );
    }
     
    update( 1, 1, n, pos[v], pos[u], k );
}
 
void update3( int u, int k )
{
    if( u == rightson )
    {
        return update( 1, 1, n, 1, n, k );
    }
     
    int l = lca( u, rightson);
     
    if( l != u )
    {
        return update( 1, 1, n, pos[u], out[u], k );
    }
     
    int son2 = find(u,rightson);
     
    update( 1, 1, n, 1, n, k );
    update( 1, 1, n, pos[son2], out[son2], -k );
}
 
int query2( int u, int v )
{
    int res = 0;
     
    while( top[u] != top[v] )
    {
        if( deep[top[u]] < deep[top[v]] )
        {
            swap( u, v );
        }
         
        res += query( 1, 1, n, pos[top[u]], pos[u] );
        u = fath[top[u]];
    }
     
    if( deep[u] < deep[v] ) 
    {
        swap( u, v );
    }
     
    res += query( 1, 1, n, pos[v], pos[u] );
     
    return res;
}
 
int query3( int u )
{
    if( u == rightson )
    {
        return query( 1, 1, n, 1, n );
    }
     
    int l = lca( u, rightson );
     
    if( l != u )
    {
        return query( 1, 1, n, pos[u], out[u] );
    }
     
    int son2 = find( u, rightson );
    int res = 0;
     
    res += query( 1, 1, n, 1, n );
    res -= query( 1, 1, n, pos[son2], out[son2] );
     
    return res;
}
 
signed main() 
{
    cin >> n;
     
    for( int i = 1; i <= n; i++ )
    {
        cin >> a[i];
    }
     
    for( int i = 1; i <= n - 1; i++ )
    {
        cin >> u;
        addedge( i + 1, u );
        addedge( u, i + 1 );
    }
     
    cin >> m;
     
    dfs1( rightson = 1 );
    dfs2( 1, 1 );
    build( 1, 1, n );
     
    for( int i = 1; i <= m; i++ )
    {
        cin >> x;
         
        if( x == 1 )
        {
            cin >> rightson;
        }
        else if( x == 2 )
        {
            cin >> u >> v >> w;
            update2( u, v, w );
        } 
        else if( x == 3 )
        {
            cin >> u >> v;
            update3( u, v );
        }
        else if( x == 4 )
        {
            cin >> u >> v;
            cout << query2( u, v ) << "\n";
        }
        else
        {
            cin >> u;
            cout << query3(u) << '\n';
        }
    }
}

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值