#define MAXN 50010
#define L(u) (u<<1)
#define R(u) (u<<1|1)
//写在类里面爆栈
int n, m, q;
int tim; //时间戳
int num[MAXN]; //树上每个节点的初始值
int siz[MAXN]; //siz[u]表示以u为根的子树的节点数
int top[MAXN]; //树链上深度最小的点
int son[MAXN]; //重儿子
int dep[MAXN]; //深度
int tid[MAXN]; //节点的时间戳
int _tid[MAXN]; //tid[i]=j表示时间戳为i的节点是j
int father[MAXN]; //父节点
bool vis[MAXN];
vector<int> edge[MAXN];
void init(int n)
{
for(int i = 1; i <= n; i++)
{
siz[i] = top[i] = son[i] = 0;
dep[i] = tid[i] = _tid[i] = father[i] = 0;
vis[i] = false;
tim = 0; //时间戳
edge[i].clear();
}
}
void addedge(int u, int v) //无根树加双向边
{
edge[u].push_back(v);
edge[v].push_back(u);
}
//树链剖分 dfs1(1,0)
void dfs1(int u, int pre)
{
vis[u] = true;
siz[u] = 1;
father[u] = pre;
dep[u] = dep[pre] + 1; //注意根节点比较特殊
int sz = edge[u].size();
for(int i = 0; i < sz; i++)
{
int v = edge[u][i];
if(v != father[u] && vis[v] == false)
{
dfs1(v, u);
siz[u] += siz[v];
if(son[u] == 0) son[u] = v;
else if(siz[son[u]] < siz[v]) son[u] = v;
}
}
}
//注意清空vis,dfs2(1,1)
void dfs2(int u, int tp)
{
vis[u] = true;
tid[u] = ++tim;
_tid[tim] = u;
top[u] = tp;
if(son[u] != 0)
dfs2(son[u], tp); //同一条重链的顶部相同
int sz = edge[u].size();
for(int i = 0; i < sz; i++)
{
int v = edge[u][i];
if(v != father[u] && v != son[u] && vis[v] == false) //注意去掉重儿子
dfs2(v, v);
}
}
void update(int u, int l, int r, int v); //线段树的更新函数
void change(int x, int y, int val)
{
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]])
swap(x, y);
update(1, tid[top[x]], tid[x], val); //dfs2时顶部先访问,故tid[top]较小
x = father[top[x]]; //因为top[x]->x路径上的所有点已经被更新了
}
if(dep[x] > dep[y]) //同一条重链上深度小的tid小
swap(x, y);
update(1, tid[x], tid[y], val);
}
//线段树部分
模板-树链剖分
最新推荐文章于 2021-07-21 22:01:14 发布