#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define lid id << 1
#define rid id << 1 | 1
using namespace std;
long long n, m, r, rank_[5211314], new_id;
//rank_表示修改后的序号对应的先前序号 new表示新序号
long long cnt, head[5211314], w[5211314];
//head表示第i个点第一条边的cnt
struct Chain_Forward_Star {
long long next;//下一条边的cnt
long long to;//这个cnt边连接的下一个节点
}pic[5211314];
struct Heavy_Light_Decompostion {
long long Father;//保存结点的父亲节点
long long Deep;//深度
long long Size;//子树节点个数
long long Heavy_Son;//重儿子
long long Top;//重链顶节点(若无重链则是他本身)
long long Id;//树链剖分后新编号
}HL_tree[5211314];
//树链剖分
struct Segment_tree {
long long l, r;
long long lazy, sum, maxn;
}Seg_tree[5211314];
inline long long read() {
long long x = 0, f = 1;
char ch = getchar();
while ( ch < '0' || ch > '9' ) {
if ( ch == '-' ) f = -1;
ch = getchar();
}
while ( ch >= '0' && ch <= '9' ) {
x = ( x << 1 ) + ( x << 3 ) + ( ch -'0' );
ch = getchar();
}
return x * f;
}//快读
void print( long long x ) {
if ( x < 0 ) putchar( '-' ), x *= -1;
if ( x > 9 ) print( x / 10 );
putchar( x % 10 + '0' );
return;
}//快输
inline void add_edge( long long v1 , long long v2 ) {
++ cnt;
pic[cnt].next = head[v1];
head[v1] = cnt;
pic[cnt].to = v2;
return;
}//链式前向星建边
inline void pushdown( long long id ) {
if ( Seg_tree[id].lazy ) {
long long temp = Seg_tree[id].lazy;
Seg_tree[lid].lazy += temp;
Seg_tree[rid].lazy += temp;
Seg_tree[lid].sum += temp * ( Seg_tree[lid].r - Seg_tree[lid].l + 1 );
Seg_tree[rid].sum += temp * ( Seg_tree[rid].r - Seg_tree[rid].l + 1 );
Seg_tree[lid].maxn += temp;
Seg_tree[rid].maxn += temp;
Seg_tree[id].lazy = 0;
}//写到这里
}
inline void pushup( long long id ) {
Seg_tree[id].sum = Seg_tree[lid].sum + Seg_tree[rid].sum;
Seg_tree[id].maxn = max( Seg_tree[lid].maxn , Seg_tree[rid].maxn );
return;
}
void build_tree( long long id , long long l , long long r ) {
Seg_tree[id].l = l;
Seg_tree[id].r = r;
long long mid = ( l + r ) >> 1;
if ( l == r ) {
Seg_tree[id].sum = Seg_tree[id].maxn = w[rank_[l]];
//因为是按第二次DFS序找,注意这里是w[rank_[l]]
return;
}
build_tree( lid , l , mid );
build_tree( rid , mid + 1 , r );
pushup( id );
return;
}
void update( long long id , long long l , long long r , long long add_num ) {
if ( Seg_tree[id].l >= l && Seg_tree[id].r <= r ) {
Seg_tree[id].sum += add_num * ( Seg_tree[id].r - Seg_tree[id].l + 1 );
Seg_tree[id].maxn += add_num;
Seg_tree[id].lazy += add_num;
return;
}
pushdown( id );
long long mid = ( Seg_tree[id].l + Seg_tree[id].r ) >> 1;
if ( l <= mid ) update( lid , l , r , add_num );
if ( r > mid ) update( rid , l , r , add_num );
pushup( id );
return;
}
long long segtree_query_sum( long long id , long long l , long long r ) {
if ( Seg_tree[id].l >= l && Seg_tree[id].r <= r ) {
return Seg_tree[id].sum;
}
pushdown( id );
long long ans = 0;
long long mid = ( Seg_tree[id].l + Seg_tree[id].r ) >> 1;
if ( l <= mid ) ans += segtree_query_sum( lid , l , r );
if ( r > mid ) ans += segtree_query_sum( rid , l , r );
return ans;
}
long long segtree_query_max( long long id , long long l , long long r ) {
if ( Seg_tree[id].l >= l && Seg_tree[id].r <= r ) {
return Seg_tree[id].maxn;
}
pushdown( id );
long long ans = -521131400000;
long long mid = ( Seg_tree[id].l + Seg_tree[id].r ) >> 1;
if ( l <= mid ) ans = max( ans , segtree_query_max( lid , l , r ) );
if ( r > mid ) ans = max( ans , segtree_query_max( rid , l , r ) );
return ans;
}
inline long long query_sum( long long x , long long y ) {
long long ans = 0;
long long left, right;
while ( HL_tree[x].Top != HL_tree[y].Top ) {
//不在一条链里
if ( HL_tree[HL_tree[x].Top].Deep < HL_tree[HL_tree[y].Top].Deep ) {
swap( x , y );
//以链顶深度大的向上走
}
left = HL_tree[HL_tree[x].Top].Id;
right = HL_tree[x].Id;
//x这条链的左右Id区间
ans = ans + segtree_query_sum( 1 , left , right );
//查询这条链的和
x = HL_tree[HL_tree[x].Top].Father;
//x跳到链顶的父亲
}
//跳出while时x与y在同一条重链上了
if ( HL_tree[x].Deep > HL_tree[y].Deep ) {
swap( x , y );
//让x成为y的祖先
}
left = HL_tree[x].Id;
right = HL_tree[y].Id;
ans += segtree_query_sum( 1 , left , right );
return ans;
}//找x到y最短路里的和
inline long long query_max( long long x , long long y ) {
long long ans = -521131400000;
long long left, right;
while ( HL_tree[x].Top != HL_tree[y].Top ) {
if ( HL_tree[HL_tree[x].Top].Deep < HL_tree[HL_tree[y].Top].Deep ) {
swap( x , y );
}
left = HL_tree[HL_tree[x].Top].Id;
right = HL_tree[x].Id;
ans = max( ans , segtree_query_max( 1 , left , right ) );
x = HL_tree[HL_tree[x].Top].Father;
}
if ( HL_tree[x].Deep > HL_tree[y].Deep ) {
swap( x , y );
}
left = HL_tree[x].Id;
right = HL_tree[y].Id;
ans = max( ans , segtree_query_max( 1 , left , right ) );
return ans;
}//找x到y最短路里的的最大值
inline void HL_update( long long x , long long y ,long long add_num ) {
long long left, right;
while ( HL_tree[x].Top != HL_tree[y].Top ) {
if ( HL_tree[HL_tree[x].Top].Deep < HL_tree[HL_tree[y].Top].Deep ) {
swap( x , y );
}
left = HL_tree[HL_tree[x].Top].Id;
right = HL_tree[x].Id;
update( 1 , left , right , add_num );
x = HL_tree[HL_tree[x].Top].Father;
}
if ( HL_tree[x].Deep > HL_tree[y].Deep ) {
swap( x , y );
}
left = HL_tree[x].Id;
right = HL_tree[y].Id;
update( 1 , left , right , add_num );
return;
}//把x到y的最短路里的每一个节点都加上add_num
void DFS_1( long long now , long long fa ) {
//now表示当前节点 fa表示爹
HL_tree[now].Father = fa;//now对应的父亲
HL_tree[now].Deep = HL_tree[fa].Deep + 1;//深度是父亲深度+1
HL_tree[now].Size = 1;//大小初始化为1(要把自己算进去)
for (long long i = head[now], v; i != 0; i = pic[i].next) {
//遍历边
v = pic[i].to;
if ( v != fa ) {
//因为是无向图,所以要注意可能有指向fa的边
DFS_1( v , now );
HL_tree[now].Size += HL_tree[v].Size;//子树已处理,所以要加上子树大小
if ( HL_tree[v].Size > HL_tree[HL_tree[now].Heavy_Son].Size ) {
HL_tree[now].Heavy_Son = v;
}
}
}
return;
}
void DFS_2( long long now , long long top ) {
//now表示当前节点 top表示当前链顶
HL_tree[now].Top = top;
HL_tree[now].Id = ++ new_id;
rank_[new_id] = now;
if ( HL_tree[now].Heavy_Son ) DFS_2( HL_tree[now].Heavy_Son , top );
//先走重儿子,目的是使重链轻链的的dfs序连续
for (long long i = head[now], v; i != 0; i = pic[i].next) {
v = pic[i].to;
if ( v != HL_tree[now].Father && v != HL_tree[now].Heavy_Son ) {
//第一个判断防止在无向图中下一个儿子自己父亲
//第二个判断表示儿子不在重链里,即不是重儿子
DFS_2( v , v );
//儿子不是重儿子则重链顶是自己
}
}
return;
}
int main()
{
n = read();
m = read();
r = read();
for (int i = 1; i <= n; ++i) {
w[i] = read();
}
for (int i = 1, a, b; i <= n - 1; ++i) {
a = read();
b = read();
add_edge( a , b );
add_edge( b , a );
}
DFS_1( r , 0 );
DFS_2( r , r );
build_tree( 1 , 1 , n );
for (long long i = 1, x, y, z, p; i <= m; ++i) {
p = read();
if ( p == 1 ) {
//表示将树从 x 到 y 结点最短路径上所有节点的值都加上 z
x = read();
y = read();
z = read();
HL_update( x , y , z );
}
else if ( p == 2 ) {
//表示求树从 x 到 y 结点最短路径上所有节点的值之和
x = read();
y = read();
print( query_sum( x , y ) );
putchar( '\n' );
}
else if ( p == 3 ) {
//表示将以 x 为根节点的子树内所有节点值都加上 z
x = read();
z = read();
update( 1 , HL_tree[x].Id , HL_tree[x].Id + HL_tree[x].Size - 1 , z );
}
else if ( p == 4 ) {
// 表示求以 x 为根节点的子树内所有节点值之和
x = read();
print( segtree_query_sum( 1 , HL_tree[x].Id , HL_tree[x].Id + HL_tree[x].Size - 1 ) );
putchar( '\n' );
}
}
return 0;
}
标签:剖分,tree,long,树链,Seg,HL,now,id,模板
From: https://www.cnblogs.com/jueqingfeng/p/17182775.html