zoukankan      html  css  js  c++  java
  • 圆方树总结

    • 圆方树:一种将由图转化而成的树,从而大大了增加题目的可解性,且大多广泛用于仙人掌图中。

    • 针对仙人掌图上的圆方树:仙人掌是指一条边至多只被一个环包含的无向图。

    • 树上的点:圆方树上分为两类点,一类是圆点,一类是方点。圆点即原图中所有的点,方点即为了去环而新添加进去的,满足一定性质的点。

    • 构造思路:圆圆边直接加入,对于仙人掌中的任意一个环,每个环上的点在圆方树上对应的圆点向这个环对应的方点连边,方点为一个新建节点。

    • 环的根:指定一个圆点为圆方树的根,把方点的父亲叫做这个方点对应的环的根。

    • 圆方边边权:若一个在环上的圆点不是环的根,它到对应方点的边权为到环的根的最短距离,环的根到环所对应的方点的边权为零。

    解题:

    • 多数是为了可以用树上的算法,例如倍增、树剖解决问题,以两点间路径的问题为例:

    • (lca) 是圆点,那么答案就是路径上的贡献;

    • (lca) 是方点,则找到进入这个环的两个点,这两个点之间的有两条路径,选择合题意的一条加入贡献。

    • 在树链剖分中,进入一个环的两个点有两种情况:一是一个为 (dfs) 序比 (lca)(1) 的点,即 (lca) 所在重链上的儿子,另一个为最后经过的 (top);二是最后经过的两个 (top)

    洛谷模板题:

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 40000 + 10;
    int n, m, q, head_g[maxn], head_t[maxn], st[17][maxn], edge_num_g, edge_num_t, dfn_num, col_num, top;
    int dfn[maxn], low[maxn], sta[maxn];
    long long deep[maxn], dis[maxn], sum[maxn], sccsum[maxn];
    
    struct Edge { int v, nxt; long long w; } edge_g[maxn << 2], edge_t[maxn << 2];
    
    inline void Add_edge_g(int u, int v, long long w) {
      edge_g[++edge_num_g].v = v, edge_g[edge_num_g].w = w, edge_g[edge_num_g].nxt = head_g[u], head_g[u] = edge_num_g;
    }
    
    inline void Add_edge_t(int u, int v, long long w) {
      edge_t[++edge_num_t].v = v, edge_t[edge_num_t].w = w, edge_t[edge_num_t].nxt = head_t[u], head_t[u] = edge_num_t;
    }
    
    inline void Tarjan(int x, int p) {
      dfn[x] = low[x] = ++dfn_num, sta[++top] = x;
      for(int i = head_g[x]; i; i = edge_g[i].nxt) if( edge_g[i].v != p ) {
        if( dfn[edge_g[i].v] == 0 ) {
          sum[edge_g[i].v] = sum[x] + edge_g[i].w, Tarjan(edge_g[i].v, x), low[x] = min(low[x], low[edge_g[i].v]);
          if( low[edge_g[i].v] > dfn[x] ) Add_edge_t(x, edge_g[i].v, edge_g[i].w), Add_edge_t(edge_g[i].v, x, edge_g[i].w);  // 树边,圆圆边加入
        }
        else if( dfn[edge_g[i].v] < low[x] ) {  // 返祖边,得环,建立方点及圆方边
          sccsum[++col_num] = sum[x] - sum[edge_g[i].v] + edge_g[i].w;  // 得环长,col_num 认为是方点编号
          for(int j = top; sta[j] != edge_g[i].v; --j) {
            int _w = min(sum[sta[j]] - sum[edge_g[i].v], sccsum[col_num] - sum[sta[j]] + sum[edge_g[i].v]); // 到此环的根的距离,即圆方边边权
            Add_edge_t(n + col_num, sta[j], _w), Add_edge_t(sta[j], n + col_num, _w);
          }
          Add_edge_t(n + col_num, edge_g[i].v, 0), Add_edge_t(edge_g[i].v, n + col_num, 0); // 环的根所对应的圆方边权为 0
          low[x] = dfn[edge_g[i].v];
        }
      }
      --top;
    }
    
    inline void Deep_fs(int x, int p) {
      for(int i = 1; i < 17; ++i) st[i][x] = st[i - 1][st[i - 1][x]];
      for(int i = head_t[x]; i; i = edge_t[i].nxt) if( edge_t[i].v != p ) {
        st[0][edge_t[i].v] = x;
        dis[edge_t[i].v] = dis[x] + edge_t[i].w, deep[edge_t[i].v] = deep[x] + 1, Deep_fs(edge_t[i].v, x);
      }
    }
    
    inline long long Querry(int x, int y) {
      int lca = 0, res = dis[x] + dis[y];
      if( deep[x] < deep[y] ) swap(x, y);
      for(int i = 16; i >= 0; --i) if( deep[st[i][x]] >= deep[y] ) x = st[i][x];
      if( x == y ) lca = x;
      else {
        for(int i = 16; i >= 0; --i) if( st[i][x] != st[i][y] ) x = st[i][x], y = st[i][y];
        lca = st[0][x];
      }
      if( lca <= n ) return res - (dis[lca] << 1);
      if( dfn[x] > dfn[y] ) swap(x, y);
      return res - dis[x] - dis[y] + min(sum[y] - sum[x], sccsum[lca - n] - sum[y] + sum[x]);
    }
    
    int main(int argc, char const *argv[])
    {
      scanf("%d%d%d", &n, &m, &q);
      for(int u, v, w, i = 1; i <= m; ++i) scanf("%d%d%d", &u, &v, &w), Add_edge_g(u, v, w), Add_edge_g(v, u, w);
      deep[1] = 1, Tarjan(1, 0), Deep_fs(1, 0);
      for(int u, v, i = 1; i <= q; ++i) scanf("%d%d", &u, &v), printf("%lld
    ", Querry(u, v));
    
      return 0;
    }
    
  • 相关阅读:
    java 基本数据类型的取值范围
    警惕自增的陷阱
    三元操作符的类型务必一致
    不要随便设置随机种子
    优先使用整形池
    IN、ANY、ALL与SOME
    第六章-序列:字符串、列表和元组 笔记
    第十二章-安全性
    第五章-数字 课后答案
    第十一章-约束、视图与事务
  • 原文地址:https://www.cnblogs.com/nanjoqin/p/11293720.html
Copyright © 2011-2022 走看看