ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

关于毛毛虫剖分

2022-07-01 17:02:32  阅读:159  来源: 互联网

标签:剖分 int top update son 100005 dfn 关于 毛毛虫


毛毛虫剖分

一种由重链剖分推广而成的树上结点重标号方法,支持 修改/查询 一只毛毛虫的信息,并且可以对毛毛虫的身体和足分别 修改/查询 不同信息 。

可以用来解决一些大力树剖也可以解决的问题。

一些定义:

  • 毛毛虫:一条树上的链和与这条链邻接的所有结点构成的集合;
  • 虫身:毛毛虫的链部分;
  • 虫足:毛毛虫除虫身的部分。

重标号方法:

  • 首先重剖求出重链。若现在递归处理到结点 u:

  • 若 u 还未被标号,则为其标号;

  • 若 u 是链头,遍历这条重链,将邻接这条链的结点依次标号;

  • 先递归重儿子,再递归轻儿子。

重标号性质:

  • 对于重链,除链头外的结点标号连续;

  • 对于任意结点,其轻儿子标号连续;

  • 对于以重链头为根的子树,与这条重链邻接的所有结点标号连续;

借此我们可以很容易地求维护每条毛毛虫的信息。

同时也能顺便维护重链链分的所有信息以及子树的所有信息(一棵子树至多剖分为三个不交区间:重链区间、邻接轻点区间、邻接轻子树区间),复杂度与重链剖分完全一样。

例题:

[NOI2021] 轻重边

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int T;
int n, m;
int ver[200005], ne[200005], head[100005], tot;
inline void link(int x, int y) {
    ver[++tot] = y;
    ne[tot] = head[x];
    head[x] = tot;
}
int siz[100005], son[100005], fa[100005], dep[100005];
void dfs1(int x, int fi) {
    siz[x] = 1;
    fa[x] = fi;
    dep[x] = dep[fi] + 1;
    for (int i = head[x]; i; i = ne[i]) {
        int u = ver[i];
        if (u == fi) continue;
        dfs1(u, x);
        siz[x] += siz[u];
        if (siz[u] > siz[son[x]]) son[x] = u;
    }
}
int top[100005];
int dfn[100005], cnt, lein[100005], leout[100005], alout[100005], subin[100005], subout[100005];
void cover(int x) {
    lein[x] = cnt + 1;
    for (int i = head[x]; i; i = ne[i]) {
        int u = ver[i];
        if (u == fa[x] || u == son[x]) continue;
        dfn[u] = ++cnt;
    }
    leout[x] = cnt;
    if (son[x]) cover(son[x]);
    alout[x] = cnt;
}
void dfs2(int x, int fi) {
    top[x] = fi;
    if (!dfn[x]) dfn[x] = ++cnt;
    if (x == top[x]) cover(x);
    subin[x] = cnt + 1;
    if (son[x]) dfs2(son[x], fi);
    for (int i = head[x]; i; i = ne[i]) {
        int u = ver[i];
        if (u == fa[x] || u == son[x]) continue;
        dfs2(u, u);
    }
    subout[x] = cnt;
}
int tree[400005], lazy[400005];
void build(int l = 1, int r = n, int i = 1) {
    tree[i] = 0;
    lazy[i] = -1;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    build(l, mid, i << 1);
    build(mid + 1, r, i << 1 | 1);
}
inline void push(int i, int l, int r) {
    int mid = (l + r) >> 1;
    tree[i << 1] = lazy[i] * (mid - l + 1);
    lazy[i << 1] = lazy[i];
    tree[i << 1 | 1] = lazy[i] * (r - mid);
    lazy[i << 1 | 1] = lazy[i];
    lazy[i] = -1;
}
void update(int fr, int to, int v, int l = 1, int r = n, int i = 1) {
    if (fr > r || to < l) return ;
    if (fr <= l && to >= r) {
        tree[i] = (r - l + 1) * v;
        lazy[i] = v;
        return ;
    }
    if (~lazy[i]) push(i, l, r);
    int mid = (l + r) >> 1;
    update(fr, to, v, l, mid, i << 1);
    update(fr, to, v, mid + 1, r, i << 1 | 1);
    tree[i] = tree[i << 1] + tree[i << 1 | 1];
}
inline void lca(int x, int y) {
    vector<int> vec;
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        update(lein[top[x]], leout[x], 0);
        update(dfn[son[x]], dfn[son[x]], 0);
        if (x != top[x]) update(dfn[son[top[x]]], dfn[x], 1);
        vec.push_back(top[x]);
        x = fa[top[x]];
    }
    if (dep[x] < dep[y]) swap(x, y);
    update(lein[y], leout[x], 0);
    update(dfn[y], dfn[y], 0);
    update(dfn[son[x]], dfn[son[x]], 0);
    if (x != y) update(dfn[son[y]], dfn[x], 1);
    for (auto it : vec) update(dfn[it], dfn[it], 1);
}
int query(int fr, int to, int l = 1, int r = n, int i = 1) {
    if (fr > r || to < l) return 0;
    if (fr <= l && to >= r) return tree[i];
    if (~lazy[i]) push(i, l, r);
    int mid = (l + r) >> 1;
    return query(fr, to, l, mid, i << 1) + query(fr, to, mid + 1, r, i << 1 | 1);
}
inline int Query(int x, int y) {
    int res = 0;
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        if (top[x] != x) res += query(dfn[son[top[x]]], dfn[x]);
        res += query(dfn[top[x]], dfn[top[x]]);
        x = fa[top[x]];
    }
    if (dep[x] < dep[y]) swap(x, y);
    if (x != y) res += query(dfn[son[y]], dfn[x]);
    return res;
}
inline void clear() {
    for (int i = 1; i <= n; i++) head[i] = 0;
    tot = 0;
    for (int i = 1; i <= n; i++) siz[i] = 0;
    for (int i = 1; i <= n; i++) son[i] = 0;
    for (int i = 1; i <= n; i++) dfn[i] = 0;
    cnt = 0;
    build();
}
inline void solve() {
    scanf("%d%d", &n, &m);
    clear();
    for (int i = 1; i < n; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        link(x, y);
        link(y, x);
    }
    dfs1(1, 1);
    dfs2(1, 1);
    while (m--) {
        int op, x, y;
        scanf("%d%d%d", &op, &x, &y);
        if (op == 1) lca(x, y);
        else printf("%d\n", Query(x, y));
    }

}
int main() {
    freopen("edge.in", "r", stdin);
    freopen("edge.out", "w", stdout);
    scanf("%d", &T);
    while (T--) solve();
    return 0;
}


标签:剖分,int,top,update,son,100005,dfn,关于,毛毛虫
来源: https://www.cnblogs.com/A-Quark/p/16435243.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有