zoukankan      html  css  js  c++  java
  • 线段树求树的直径

    线段树求直径可以求任意子树(包括连子树都不算的分散节点集合)的直径,适用范围广。

    线段树的每个节点所对应的区间$[L, R]$,指代了$Dfn$在$[L, R]$内节点,其中线段树上每个节点存储了$diam$(当前区间直径)及$lp, rp$(当前直径对应的左右端点),每次$Merge$操作分为全左区间、全右区间和横跨两个区间作讨论,对于第三种情况,选择两侧原直径端点求$Dist$取最值即可,正确性显然,查询直接通过$Dfn$查询即可。

    当然可能有一些区间内的点不连通,先当作它们连通即可。

    对于删除某些子树,相当于把整棵树分为$n$部分,查询每个部分,全部$Merge$起来即可。

    · 例题 

    Snow的追寻

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <cmath>
      6 
      7 #define lson root << 1
      8 #define rson root << 1 | 1
      9 
     10 using namespace std;
     11 
     12 const int MAXN = 1e05 + 10;
     13 const int MAXM = 1e05 + 10;
     14 
     15 struct LinkedForwardStar {
     16     int to;
     17 
     18     int next;
     19 } ;
     20 
     21 LinkedForwardStar Link[MAXM << 1];
     22 int Head[MAXN]= {0};
     23 int size = 0;
     24 
     25 void Insert (int u, int v) {
     26     Link[++ size].to = v;
     27     Link[size].next = Head[u];
     28 
     29     Head[u] = size;
     30 }
     31 
     32 const int Root = 1;
     33 
     34 int Deep[MAXN];
     35 int Size[MAXN];
     36 int Val[MAXN << 1];
     37 int Dfn[MAXN], DDfn[MAXN];
     38 int Rank[MAXN];
     39 int dfsord = 0, dod2 = 0;
     40 
     41 void DFS (int root, int father) {
     42     Size[root] = 1;
     43     Dfn[root] = ++ dfsord;
     44     Rank[dfsord] = root;
     45     DDfn[root] = ++ dod2;
     46     Val[dod2] = Deep[root];
     47     for (int i = Head[root]; i; i = Link[i].next) {
     48         int v = Link[i].to;
     49         if (v == father)
     50             continue;
     51 
     52         Deep[v] = Deep[root] + 1;
     53         DFS (v, root);
     54         Size[root] += Size[v];
     55         Val[++ dod2] = Deep[root];
     56     }
     57 }
     58 
     59 int ST[MAXN << 1][30];
     60 
     61 void RMQ () {
     62     for (int i = 1; i <= dod2; i ++)
     63         ST[i][0] = Val[i];
     64     for (int j = 1; j <= 20; j ++)
     65         for (int i = 1; i <= dod2; i ++)
     66             if (i + (1 << (j - 1)) <= dod2)
     67                 ST[i][j] = min (ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
     68 }
     69 
     70 int Query (int L, int R) {
     71     int k = log2 (R - L + 1);
     72     return min (ST[L][k], ST[R - (1 << k) + 1][k]);
     73 }
     74 
     75 int Dist (int x, int y) {
     76     if (DDfn[x] > DDfn[y])
     77         swap (x, y);
     78 
     79     int deeplca = Query (DDfn[x], DDfn[y]);
     80     return Deep[x] + Deep[y] - 2 * deeplca;
     81 }
     82 
     83 struct Node {
     84     int diam;
     85     int lp, rp;
     86 
     87     Node () {
     88         diam = 0;
     89         lp = rp = 0;
     90     }
     91 
     92     Node (int fdiam, int flp, int frp) :
     93         diam (fdiam), lp (flp), rp (frp) {}
     94 } ;
     95 
     96 Node Tree[MAXN << 2];
     97 
     98 
     99 Node Merge (Node s1, Node s2) {
    100     if (s1.diam == - 1)
    101         return s2;
    102     Node news = s1.diam >= s2.diam ? s1 : s2; // 以下讨论
    103     if (Dist (s1.lp, s2.lp) > news.diam)
    104         news = Node (Dist (s1.lp, s2.lp), s1.lp, s2.lp);
    105     if (Dist (s1.lp, s2.rp) > news.diam)
    106         news = Node (Dist (s1.lp, s2.rp), s1.lp, s2.rp);
    107     if (Dist (s1.rp, s2.lp) > news.diam)
    108         news = Node (Dist (s1.rp, s2.lp), s1.rp, s2.lp);
    109     if (Dist (s1.rp, s2.rp) > news.diam)
    110         news = Node (Dist (s1.rp, s2.rp), s1.rp, s2.rp);
    111 
    112     return news;
    113 }
    114 
    115 void Build (int root, int left, int right) {
    116     Tree[root] = Node ();
    117 
    118     if (left == right) {
    119         Tree[root].diam = 0;
    120         Tree[root].lp = Tree[root].rp = Rank[left];
    121         return ;
    122     }
    123 
    124     int mid = (left + right) >> 1;
    125     Build (lson, left, mid);
    126     Build (rson, mid + 1, right);
    127 
    128     Tree[root] = Merge (Tree[lson], Tree[rson]);
    129 }
    130 
    131 Node Query (int root, int left, int right, int L, int R) {
    132     if (L == left && R == right)
    133         return Tree[root];
    134 
    135     int mid = (left + right) >> 1;
    136     if (R <= mid)
    137         return Query (lson, left, mid, L, R);
    138     else if (L > mid)
    139         return Query (rson, mid + 1, right, L, R);
    140     else
    141         return Merge (Query (lson, left, mid, L, mid), Query (rson, mid + 1, right, mid + 1, R));
    142 }
    143 
    144 int N, Q;
    145 
    146 int getnum () {
    147     int num = 0;
    148     char ch = getchar ();
    149 
    150     while (! isdigit (ch))
    151         ch = getchar ();
    152     while (isdigit (ch))
    153         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
    154 
    155     return num;
    156 }
    157 
    158 int main () {
    159     // freopen ("Input.txt", "r", stdin);
    160 
    161     N = getnum (), Q = getnum ();
    162 
    163     for (int i = 1; i < N; i ++) {
    164         int u, v;
    165         u = getnum (), v = getnum ();
    166         Insert (u, v), Insert (v, u);
    167     }
    168 
    169     DFS (Root, 0);
    170     RMQ ();
    171 
    172     Build (Root, 1, dfsord);
    173     for (int Case = 1; Case <= Q; Case ++) {
    174         int x, y;
    175         x = getnum (), y = getnum ();
    176 
    177         Node res = Node (- 1, - 1, - 1);
    178         if (Dfn[x] > Dfn[y])
    179             swap (x, y);
    180         int sx = Dfn[x], ex = sx + Size[x] - 1;
    181         int sy = Dfn[y], ey = sy + Size[y] - 1;
    182         if (sx > 1) // 第一部分
    183             res = Merge (res, Query (Root, 1, dfsord, 1, sx - 1));
    184         if (ex + 1 < sy) // 第二部分
    185             res = Merge (res, Query (Root, 1, dfsord, ex + 1, sy - 1));
    186         int fen = max (ex, ey);
    187         if (fen < dfsord) // 第三部分
    188             res = Merge (res, Query (Root, 1, dfsord, fen + 1, dfsord));
    189         printf ("%d
    ", res.diam == - 1 ? 0 : res.diam);
    190     }
    191 
    192     return 0;
    193 }
    194 
    195 /*
    196 5 2
    197 1 3
    198 3 2
    199 3 4
    200 2 5
    201 2 4
    202 5 4
    203 */
    Snow的追寻
  • 相关阅读:
    Redis
    Linux 命令
    Linux 命令
    Networking
    Networking
    MySQL(5.6) 函数
    MySQL 中事务、事务隔离级别详解
    程序人生:搜索引擎被禁用,你还会写代码吗?
    程序人生:搜索引擎被禁用,你还会写代码吗?
    程序员幽默:老板让明天带条鱼来大家观察
  • 原文地址:https://www.cnblogs.com/Colythme/p/9881092.html
Copyright © 2011-2022 走看看