算法
#define ls l,m,rt<<1 //左儿子
#define rs m+1,r,rt<<1|1 //右儿子
int a[N]; //点信息
int sum[N<<2],add[N<<2];//区间信息
const int N=10000;
vector<int>g[N];//邻接表
int cnt; //dfs标号
int f[N]; //保存结点u的父亲节点
int d[N]; //保存结点u的深度值
int size[N];//保存以u为根的子树节点个数
int son[N];//保存重儿子
int rk[N];//保存当前dfs标号在树中所对应的节点
int id[N];//保存树中每个节点剖分以后的新编号(DFS的执行顺序)
int top[N];//保存当前节点所在链的顶端节点
void dfs1(int u,int fa,int depth)
{
f[u]=fa;
d[u]=depth;
size[u]=1; //这个点本身size=1
for(int i=0;i<g[u].size;i++){
int v=g[u][i];
if(v==fa)
continue;
dfs1(v,u,depth+1);
size[u]+=size[v]; //子节点的size已被处理,用它来更新父节点的size
if(size[v]>size[son[u]])//更新结点u的重儿子
son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
id[u]=++cnt;//树中编号为u的结点在线段树中的编号
rk[cnt]=u;//线段树中编号为cnt的结点在树中的编号
if(!son[u])
return;
/*选择优先进入重儿子来保证一条重链上各个节点dfs序连续,
一个点和它的重儿子处于同一条重链,所以重儿子所在重链的顶端还是t*/
dfs2(son[u],t);
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(v!=son[u]&&v!=f[u])
dfs2(v,v); //一个点位于轻链底端,那么它的top必然是它本身
}
}