Loj#139 树链剖分

2024-04-03 07:32
文章标签 树链 剖分 139 loj

本文主要是介绍Loj#139 树链剖分,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接

问题分析

一道比较标准的模板题。唯一需要考虑的是换根操作。

发现换根对链上的操作并没有影响,考虑对树上以\(u\)为根子树的影响。设原树上以\(u\)为根的子树是\(T\)。如果新的根在\(T\)的外部,那么以\(u\)为根的子树不变。如果新根就是\(u\),那么子树就是整棵树。否则,取原树中\(u\)的一个儿子\(v\)\(v\)包含新的根,那么新的以\(u\)为根的子树就是整棵树去掉原树中以\(v\)为根的子树。所以我们其实并不需要改变树的结构,只需要记录根节点位置就好。

参考程序

#include <bits/stdc++.h>
#define LL long long
using namespace std;const int Maxn = 100010;
struct edge {int To, Next;edge() {}edge( int _To, int _Next ) : To( _To ), Next( _Next ) {}
};
edge Edge[ Maxn << 1 ];
int Start[ Maxn ], Used;
int A[ Maxn ], N, M, Root, Cnt;
int Size[ Maxn ], Son[ Maxn ], Father[ Maxn ], Deep[ Maxn ], Top[ Maxn ], Ind[ Maxn ], Ref[ Maxn ], Max[ Maxn ];
LL Sum[ Maxn << 2 ], Tag[ Maxn << 2 ];inline void AddEdge( int x, int y ) {Edge[ ++Used ] = edge( y, Start[ x ] );Start[ x ] = Used;return;
}
void Dfs1( int Index, int Fa ) {Deep[ Index ] = Deep[ Fa ] + 1;Size[ Index ] = 1;Father[ Index ] = Fa;for( int T = Start[ Index ]; T; T = Edge[ T ].Next ) {Dfs1( Edge[ T ].To, Index );if( Size[ Edge[ T ].To ] > Size[ Son[ Index ] ] ) Son[ Index ] = Edge[ T ].To;Size[ Index ] += Size[ Edge[ T ].To ];}return;
}
void Dfs2( int Index ) {Ind[ Index ] = ++Cnt;Ref[ Cnt ] = Index;if( Son[ Index ] ) {Top[ Son[ Index ] ] = Top[ Index ];Dfs2( Son[ Index ] );}for( int T = Start[ Index ]; T; T = Edge[ T ].Next ) {if( Edge[ T ].To == Son[ Index ] ) continue;Top[ Edge[ T ].To ] = Edge[ T ].To;Dfs2( Edge[ T ].To );}Max[ Index ] = Cnt;return;
}
void Build( int Index, int Left, int Right ) {if( Left == Right ) {Sum[ Index ] = A[ Ref[ Left ] ];return;}int Mid = ( Left + Right ) >> 1;Build( Index << 1, Left, Mid );Build( Index << 1 | 1, Mid + 1, Right );Sum[ Index ] = Sum[ Index << 1 ] + Sum[ Index << 1 | 1 ];return;
}
void TagDown( int Index, int Left, int Right ) {if( Left == Right ) return;if( Tag[ Index ] == 0 ) return;int Mid = ( Left + Right ) >> 1;Tag[ Index << 1 ] += Tag[ Index ];Tag[ Index << 1 | 1 ] += Tag[ Index ];Sum[ Index << 1 ] += ( Mid - Left + 1 ) * Tag[ Index ];Sum[ Index << 1 | 1 ] += ( Right - Mid ) * Tag[ Index ];Tag[ Index ] = 0;return;
}
void Add( int Index, int Left, int Right, int L, int R, int K ) {if( L > R ) return;TagDown( Index, Left, Right );if( L <= Left && Right <= R ) {Sum[ Index ] += K * ( Right - Left + 1 );Tag[ Index ] += K;return;}int Mid = ( Left + Right ) >> 1;if( L <= Mid ) Add( Index << 1, Left, Mid, L, R, K );if( R > Mid ) Add( Index << 1 | 1, Mid + 1, Right, L, R, K );Sum[ Index ] = Sum[ Index << 1 ] + Sum[ Index << 1 | 1 ];return;
}
LL Query( int Index, int Left, int Right, int L, int R ) {if( L > R ) return 0;TagDown( Index, Left, Right );if( L <= Left && Right <= R ) return Sum[ Index ];LL Ans = 0; int Mid = ( Left + Right ) >> 1;if( L <= Mid ) Ans += Query( Index << 1, Left, Mid, L, R );if( R > Mid ) Ans += Query( Index << 1 | 1, Mid + 1, Right, L, R );return Ans;
}
void AddLink( int u, int v, int k ) {while( Top[ u ] != Top[ v ] ) {if( Deep[ Top[ u ] ] < Deep[ Top[ v ] ] ) swap( u, v );Add( 1, 1, N, Ind[ Top[ u ] ], Ind[ u ], k );u = Father[ Top[ u ] ];}if( Deep[ u ] > Deep[ v ] ) swap( u, v );Add( 1, 1, N, Ind[ u ], Ind[ v ], k );return;
}
int Get( int y, int x ) {int Last = 0;while( Top[ x ] != Top[ y ] ) {Last = Top[ x ];x = Father[ Top[ x ] ];}if( x == y ) return Last;return Son[ y ];
}
void AddSubTree( int u, int k ) {if( u == Root ) {Add( 1, 1, N, 1, N, k );return;}if( Ind[ Root ] < Ind[ u ] || Ind[ Root ] > Max[ u ] ) {Add( 1, 1, N, Ind[ u ], Max[ u ], k );return;}int T = Get( u, Root );Add( 1, 1, N, 1, Ind[ T ] - 1, k );Add( 1, 1, N, Max[ T ] + 1, N, k );return;
}
LL QueryLink( int u, int v ) {LL Ans = 0;while( Top[ u ] != Top[ v ] ) {if( Deep[ Top[ u ] ] < Deep[ Top[ v ] ] ) swap( u, v );Ans += Query( 1, 1, N, Ind[ Top[ u ] ], Ind[ u ] );u = Father[ Top[ u ] ];}if( Deep[ u ] > Deep[ v ] ) swap( u, v );Ans += Query( 1, 1, N, Ind[ u ], Ind[ v ] );return Ans;
}
LL QuerySubTree( int u ) {if( u == Root )return Query( 1, 1, N, 1, N );if( Ind[ Root ] < Ind[ u ] || Ind[ Root ] > Max[ u ] )return Query( 1, 1, N, Ind[ u ], Max[ u ] );int T = Get( u, Root );return Query( 1, 1, N, 1, Ind[ T ] - 1 ) + Query( 1, 1, N, Max[ T ] + 1, N );
}
int main() {scanf( "%d", &N );Root = 1;for( int i = 1; i <= N; ++i ) scanf( "%d", &A[ i ] ); for( int i = 1; i < N; ++i ) {int x; scanf( "%d", &x );AddEdge( x, i + 1 );}Dfs1( Root, 0 );Top[ Root ] = Root;Dfs2( Root );Build( 1, 1, N );scanf( "%d", &M );for( int i = 1; i <= M; ++i ) {int Opt; scanf( "%d", &Opt );if( Opt == 1 ) scanf( "%d", &Root );if( Opt == 2 ) {int x, y, k; scanf( "%d%d%d", &x, &y, &k );AddLink( x, y, k );}if( Opt == 3 ) {int x, k; scanf( "%d%d", &x, &k );AddSubTree( x, k );}if( Opt == 4 ) {int u, v; scanf( "%d%d", &u, &v );printf( "%lld\n", QueryLink( u, v ) );}if( Opt == 5 ) {int u; scanf( "%d", &u );printf( "%lld\n", QuerySubTree( u ) );}}return 0;
}

转载于:https://www.cnblogs.com/chy-2003/p/11315302.html

这篇关于Loj#139 树链剖分的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/872278

相关文章

树链剖分 + 后缀数组 - E. Misha and LCP on Tree

E. Misha and LCP on Tree  Problem's Link   Mean:  给出一棵树,每个结点上有一个字母。每个询问给出两个路径,问这两个路径的串的最长公共前缀。 analyse: 做法:树链剖分+后缀数组. 记录每条链的串,正反都需要标记,组成一个长串. 然后记录每条链对应的串在大串中的位置,对大串求后缀数组,最后询问就是在一些链

【HDU】5029 Relief grain 树链剖分+离线标记法

传送门:【HDU】5029 Relief grain 题目分析:这题的方法太美妙了! 首先看到这是一颗树,那么很容易想到树链剖分。然后想到可以将查询排个序,然后每一种查询执行完以后更新每个点的最优值。但是这样进行的复杂度太高!尤其是当z给的没有一样的时候尤其如此。 那么我们是否可以找到更加高效的算法? 答案是肯定的! 先简化一下问题,如果这些操作是在线段上进行的,我们怎么求解?

【HDU】5221 Occupation【树链剖分】

传送门:【HDU】5221 Occupation 题目分析: 最直接的想法,用一棵树链剖分维护路径,一棵dfs序线段树维护子树。因为每次最多修改一个点,所以修改的时候我们暴力修改每个点就可以了。 my  code: my~~code: #pragma comment(linker, "/STACK:102400000,102400000")#include <stdio.h>#in

【HDU】5436 Transmigration tree【树链剖分+dp+rmq】

题目链接:【HDU】5436 Transmigration tree #pragma comment(linker, "/STACK:16777216")#include <stdio.h>#include <string.h>#include <vector>#include <algorithm>using namespace std ;typedef long long LL ;

【HDU】5566 Clarke and room【树链剖分+AC自动机】

题目链接:Clarke and room #include <bits/stdc++.h>using namespace std ;typedef long long LL ;#define ls ( o << 1 )#define lson ls , l , m#define rs ( o << 1 | 1 )#define rson rs , m + 1 , r#define rt

Open3D mesh 模型精细化处理--中点剖分

目录 一、概述 1.1原理 1.2实现步骤 二、代码实现 2.1关键函数 输入参数 输出参数 三、实现效果 3.1原始mesh 3.2精细化mesh Open3D点云算法汇总及实战案例汇总的目录地址: Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客 一、概述         在三维模型处理过程中,精细化处理(subdivision)是一个

139.单词拆分

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 排序问题:有顺序,先遍历背包容量,再遍历数组 组合相反 class Solution {public boolean wordBreak(String s, List<String>

Dominant Indices【模板】长链剖分

~~~~~      Dominant Indices ~~~~~      总题单链接 对比重链剖分和长链剖分 ~~~~~      什么是重链剖分:根据子树的大小将树拆成多条互不相交的链。 ~~~~~      什么是长链剖分:根据字数的深度将树拆成多条互不相交的链。 ~~~~~      重链剖分中的重儿子:子树大小最大的儿子。 ~~~~~      长链剖分中的重儿子:

NYOJ-题目(Math)--139-------------------------我排第几个

package org.acm.math;// 思路:康托展开,先准备1-12的阶乘/** 康托展开的例子:* 如我想知道321是{1,2,3}中第几个小的数可以这样考虑 :* 第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。* 所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,* 所以有1*1!=1 所以小于321的{1,2,

hdu5052 Yaoge’s maximum profit 树链剖分

一棵树上,从u走到v,在某点买入,咋之后的某点卖出,求最大利润。 维护正着走和反着走的最大利润。 #include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>#include<vector>#include<set>#include<map>#include<que