首页 > 其他分享 >基环树

基环树

时间:2024-07-20 10:19:51浏览次数:8  
标签:环上 idx int son 基环树 add

基环树

定义

在树形结构中添加一条边形成的图。

分类

  1. 无向图基环树
  2. 内向基环树,每个点的出度为 1。
  3. 外向基环树,每个点的入度为 1。

image

找环:

方法1:无向图基环树找环。

拓扑排序,去掉环以外的点,剩下的就是一个那个环。

方法2:有向图和无向图均适用。

原理:在搜索树中检查一个点 \(x\) 的子节点 \(son\) 是否深度更浅。

方法3:Tarjan 改造版本。

原理:从环上某点 \(x\) 沿着某个方向 \(y\),当 \(x\) 沿另一侧到达点 \(y\) 时,会出现 \(dfn[y] > dfn[x]\),说明是个环。

使用技巧

  1. 把环当作根结点,分成环上的点和环上点的子树;
  2. 把环斩断,变成 1 棵树处理。

例题

P2607 骑士

  1. 每个点和其憎恨的点不能同时选择;
  2. 连无向边,得到基环树;
  3. 任意枚举一条环上的边以及其端点 \(x\) 和 \(y\);
  4. 分别从 \(x\) 和 \(y\) 跑一遍树形 DP 即可。
#include <bits/stdc++.h>

using namespace std;
using i64 = long long;

const int N = 1000010, M = 2000010;

struct edge {
    int to, next;
} e[M];

int head[N], idx = 1;

void add(int u, int v) {
    idx++, e[idx].to = v, e[idx].next = head[u], head[u] = idx;
}

int n, w[N];
bool vis[N];
int del = -1, del_u = -1, del_v = -1;

void dfs(int u, int last_edge) {
    // cout << u << endl;
    vis[u] = true;
    for (int i = head[u]; i; i = e[i].next) {
        if (i == (last_edge ^ 1)) continue;
        int to = e[i].to;
        if (!vis[to]) dfs(to, i);
        else {
            del = i, del_u = e[i ^ 1].to, del_v = e[i].to;
            // cout << last_edge << endl;
            // cout << "SHA" << del_u << ' ' << del_v << endl;
        }
    }
}

i64 f[N][2];

void dfs2(int u, int last_edge) {
    // cout << u << ' ' << last_edge << endl;
    f[u][0] = 0, f[u][1] = w[u];
    for (int i = head[u]; i; i = e[i].next) {
        if (i == del || i == (del ^ 1) || i == (last_edge ^ 1)) continue;
        int to = e[i].to;
        dfs2(to, i);
        f[u][0] += max(f[to][1], f[to][0]);
        f[u][1] += f[to][0];
    }
}

int main() {
    // freopen("a.in", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        int son;
        cin >> w[i] >> son;
        add(i, son);
        add(son, i);
    }

    i64 ans = 0;

    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            del = -1, del_u = -1, del_v = -1;
            dfs(i, -1);
            // cout << del_u << ' ' << del_v << endl;
            i64 tmp = 0;
            dfs2(del_u, -1);
            tmp = max(tmp, f[del_u][0]);
            dfs2(del_v, -1);
            tmp = max(tmp, f[del_v][0]);
            ans += tmp;
        }
    }
    cout << ans << '\n';
    return 0;
}

标签:环上,idx,int,son,基环树,add
From: https://www.cnblogs.com/Yuan-Jiawei/p/18310276

相关文章

  • 基环树
    在树形结构中添加1条边形成的图分类:1.无向图基环树2.内向基环树,每个点出度为1的情况一棵内向基环树3.外向基环树,每个点入度为1的情况找环方法1:无向基环树找环1.统计节点的度数deg[i]2.将度数为1的点入队3.循环从队首取出节点x并将x的邻接点y度数减14.若deg[y]==1......
  • 基环树和笛卡尔树
    基环树就是比平常的树多一条边,有\(n\)条边,也就有一个环在里面。基本思想就是断环,跑树形\(dp\),或者用拓扑排序判环去跑环形\(dp\)。树的直径今天才了解到的,用两遍\(dfs\)跑。首先第一遍找到离根节点最远的节点\(u_1\),然后再从\(u_1\)找到离它最远的节点\(u_2\),那么......
  • 基环树和笛卡尔树
    1.基环树定义:有\(n\)个点和\(n\)条边的图,就是给树连了一条边,此时图中恰好只有一个环解决这类问题时,通常断环,变成普通的树的问题,然后再特殊处理环P2607[ZJOI2008]骑士click断环成树后就跟没上司一样是个树形dp,注意森林,longlong就行了,具体细节见这里P5022[NOIP2018提高组......
  • 基环树
    基环树1.定义基环树是一个由n个点及n条边组成的连通图,其比树多出一条边,所以称作基环树。2.分类基环树分为无向基环树和有向基环树。而有向基环树又分为内向基环树和外向基环树。内向基环树,即每个点出度为1的基环树;外向基环树,即每个点入度为1的基环树。3.解决方式对于有关......
  • 基环树
    基环树的定义为:一个有向或无向图中,只含有一个环的图,形式化的表达为:关于这种形状关键点主要在于找环,那么我们可以一步一步的去寻找,当这个点走着走着走到了某个环里,我们可以直接遍历整个环,然后打个标记,这样环就找到了具体的例题:E-ReachabilityinFunctionalGraph本题就是一......
  • 基环树找环
    abc167_dTeleporter#include<bits/stdc++.h>#defineptprintf(">>>")#definemid(((l)+(r))/2)usingnamespacestd;typedeflonglongll;typedeflongdoubleld;constllN=1e6+10,inf=1e18+10,mod=1e9+7;vector<ll>G[N];map&......
  • 置换 & 基环树题
    T1Statement给一个长度为\(n(\le10^5)\)的排列\(\{a_i\}\)。求一个排列\(\{b_i\}\),使得\(a_i=b_{b_i}\),或输出不存在。Solution先把所有排列变成置换对于任意排列\(\{p_i\}\),它转成置换后都是\(i\top_i\),故有\(i\top_i\top_{p_i}\top_{p_{p_i}}\to...\)所以所有......
  • 基环树算法总结
    基环树算法总结一、什么是基环树基环树,顾名思义,有两个要素:环和树。因此,基环树就是一棵树的一个节点,扩成一个环,做题时,多棵基环树组成的基环树森林,常以如下方式出现:每个点只有一个出边。每个点只有一个入边。图中一共有\(n\)个点,\(n\)条边。那么,基环树类型的题目应该怎......
  • 基环树
    byDuck.感觉都是神秘乱搞。一般的处理方式:把整个环当成根。断环。CF711DDirectedRoads正难则反,考虑统计成环的数量。我们先把环搜出来,那么环上的边只能有全部顺时针或者全部逆时针两种方向,环外的边任意。设环长为\(L\),那么就有\(2^{n-L}\times2\)种有环的情况,从而......
  • 基环树小结
    基环树就是根节点基于环生长的一棵树,特点是\(n\)个节点\(n\)条边。如果\(n\)个节点\(n\)条边的图不联通那么是一个基环森林。很好证明,\(n\)个点\(n-1\)条边的联通图仅能是一棵树,现在从任一点引出一条边到任一点,由于两点先前一定联通,则在连接后原路径上的任意两点均有......