线段树求树的直径

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

线段树的每个节点所对应的区间$[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\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 */
Snow的追寻

 

posted @ 2018-10-31 09:22  Colythme  阅读(371)  评论(0编辑  收藏  举报