线段树求树的直径
线段树求直径可以求任意子树(包括连子树都不算的分散节点集合)的直径,适用范围广。
线段树的每个节点所对应的区间$[L, R]$,指代了$Dfn$在$[L, R]$内节点,其中线段树上每个节点存储了$diam$(当前区间直径)及$lp, \ rp$(当前直径对应的左右端点),每次$Merge$操作分为全左区间、全右区间和横跨两个区间作讨论,对于第三种情况,选择两侧原直径端点求$Dist$取最值即可,正确性显然,查询直接通过$Dfn$查询即可。
当然可能有一些区间内的点不连通,先当作它们连通即可。
对于删除某些子树,相当于把整棵树分为$n$部分,查询每个部分,全部$Merge$起来即可。
· 例题
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\n", 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 */