题目
luoguP2146 [NOI2015]软件包管理器
luoguP2590 [ZJOI2008]树的统计
luoguP3038 [USACO11DEC]牧草种植Grass Planting
luoguP3178 [HAOI2015]树上操作
luoguP3258 [JLOI2014]松鼠的新家
luoguP3833 [SHOI2012]魔法树
luoguP3950 部落冲突
题解
软件包管理器
牧草种植
树上操作
松鼠的新家
魔法树
部落冲突
核心代码
dfs1
//第一次dfs维护出fa,dep,siz,son四个数组
//fa[u]:u的父节点,dep[u]:u的深度,这个变量后面在修改链上信息时会用到
//siz[u]:u的子树大小(包括u),son[u]:u的重儿子(重链剖分)
void dfs1(int u,int f){
fa[u]=f;dep[u]=dep[f]+1;siz[u]=1;son[u]=0;
for(int i=head[u];i!=-1;i=edge[i].nxt){
int v=edge[i].e;
if(v==f)continue;
dfs1(v,u);
siz[u]+=siz[v];
son[u]=((siz[v]>siz[son[u]])?v:son[u]);
}
}
dfs2
//第二个dfs维护出seg,rev,top三个数组
//dfs(u)维护出u的子树的相关标记,这就意味着要在调用函数之前给起始(根)节点赋值
//seg[u]:点u在剖分后区间的位置,seg[0]被用作计数变量,记录区间中点的个数
//rev[u]:区间中第u个位置存放的点
//top[u]:点u所在重链的链头
void dfs2(int u,int f){
if(son[u]){//一定要先维护重儿子的标记,使得在线段树区间内重链连续排列
seg[son[u]]=++seg[0];
rev[seg[0]]=son[u];
top[son[u]]=top[u];
dfs2(son[u],u);
}
for(int i=head[u];i!=-1;i=edge[i].nxt){//维护完重儿子后再维护轻儿子
int v=edge[i].e;
if(!top[v]){//排除掉重儿子和父节点
seg[v]=++seg[0];
rev[seg[0]]=v;
top[v]=v;
dfs2(v,u);
}
}
}
树剖支持的相关操作
- 树上链信息的维护
- 树上子树信息的维护
- 未完待续…
对树剖的一点理解
两个字,哈希
即,利用某些数据结构(线段树,Splay……)处理区间问题的优势来处理树上的信息处理问题,具体做法就是按照某些规则(如轻重链剖分,长短链剖分……)将树分成有规律的几块放在一个区间里,然后用合适的数据结构去处理。
T o B e C o n t i n u e . . . To Be Continue... ToBeContinue...