2024.3.14 树链剖分 and 树上启发式合并

树链剖分
//参考 https://oi-wiki.org/graph/hld/#%E4%BE%8B%E9%A2%98
//例题 //https://loj.ac/p/10138 https://www.luogu.com.cn/problem/P3379
vector<int>G[N];
int son[N];
int siz[N];
int fa[N];
int dep[N];
void dfs1(int o) {
  	son[o] = -1;
  	siz[u] = 1;
  	for (int v:G[u]){
      	if(dep[v]) continue;
      	fa[v]=u;
      	dep[v]=dep[u]+1;
      	dfs1(v);
      	siz[u]+=siz[v];
      	if(!son[u]||siz[v]>size[son[u]]) son[u]=v;
  }
}
void dfs2(int u, int f) {
  	top[u] = f;
  	dfn[u] = ++cnt;
  	rnk[cnt] = u;
  	if (!son[u]) return;
  	dfs2(son[u], f);
  	for (int v : G[u]) {
      	if(v==son[u]||v==f) continue;
      	dfs2(v,v);
  	}
}
// 因为重链是连续的dfn序列,所以根据这个特性,将树变为一个序列配合线段树,可以查询点、边的(最大值,和)
// 原理:位于轻链,暴力慢慢移动到重链;位于重链,线段树优化移动到重链头,直到两者位于同一条重链,再用线段树线段树计算距离
// st 是线段树结构体
int querymax(int x, int y) {
  int ret = -inf, fx = top[x], fy = top[y];
  while (fx != fy) {
    if (dep[fx] >= dep[fy])
      ret = max(ret, st.query1(1, 1, n, dfn[fx], dfn[x])), x = fa[fx];
    else
      ret = max(ret, st.query1(1, 1, n, dfn[fy], dfn[y])), y = fa[fy];
    fx = top[x];
    fy = top[y];
  }
  if (dfn[x] < dfn[y])
    ret = max(ret, st.query1(1, 1, n, dfn[x], dfn[y]));
  else
    ret = max(ret, st.query1(1, 1, n, dfn[y], dfn[x]));
  return ret;
}
树上启发式合并:
//https://codeforces.com/problemset/problem/600/E
void update(int u, int v) {
    cnt[a[u]] += v;
    if(cnt[a[u]] > maxv) maxv = cnt[a[u]], sum = a[u];
    else if(cnt[a[u]] == maxv) sum += a[u];
}
int L[N],R[N];
int dfn[N],tot;
int siz[N];
void dfs1(int u, int fa)
{
    siz[u] = 1;
    L[u] = ++tot;
    dfn[ts] = u;
    for (int v:G[u]){
        if(v == fa) continue;
        dfs1(v,u);
        size[u]+=siz[v];
        if(siz[v]>sz[son[u]]) son[u]=j;
    }
    R[u]=tot;
}
void dfs2(int u, int fa, int del) {
    for (int v:G[u]){
        if(v==son[u]||v==fa) continue;
        dfs2(v,u,1);
    }
    if(son[u]) dfs2(son[u], u, 0);
    for (int v:G[u]){
        if(v==son[u]||v==fa) continue;
        for (int i=L[v];i<=R[v];i++){
            update(dfn[i], 1); // 子树合并
        }
        dfs2(v,u,1);
    }
    update(u, 1);
    ans[u] = sum;
    if(del) {
        for(int i=L[u];i<=R[u];i++) 
            update(dfn[i], -1); // 子树合并
        maxv = sum = 0;
    }
}

过知识点

posted @ 2024-03-15 00:12  O_JF?  阅读(4)  评论(0编辑  收藏  举报