求编号在区间[l, r]之间的两两lca的深度最大值。
例题。
解:口胡几种做法。前两种基于莫队,第三种是启发式合并 + 扫描线,第四种是lct + 线段树。
①:
有个结论就是这个答案一定是点集中DFS序相邻的两个点的lca。于是开个数据结构,以DFS序为key维护点集,找前驱后继,额外用一个数据结构维护所有lca的深度,取最大值即可。外面套莫队就做完了。
实现上这两个数据结构都可以用树状数组。
1 #include <bits/stdc++.h> 2 3 #define out(a) std::cerr << #a" = " << a << std::endl; 4 5 template <class T> inline void read(T &x) { 6 x = 0; 7 char c = getchar(); 8 while(c < '0' || c > '9') c = getchar(); 9 while(c >= '0' && c <= '9') { 10 x = x * 10 + c - 48; 11 c = getchar(); 12 } 13 return; 14 } 15 16 const int N = 80010; 17 18 struct Edge { 19 int nex, v; 20 }edge[N << 1]; int tp; 21 22 int e[N], pos[N], pos2[N], num, num2, fr[N], ans[N], id[N], ST[N << 1][20], d[N], pw[N << 1], n; 23 /*std::set<int> st; /// save pos 24 std::set<int>::iterator it;*/ 25 /*std::multiset<int> Ans; 26 std::multiset<int>::iterator it2;*/ 27 28 namespace Ans { 29 int ta[N], cnt; 30 inline void add(int i) { 31 ++cnt; 32 // printf("Ans : add : %d \n", i); 33 for(; i <= n; i += i & (-i)) { 34 ta[i]++; 35 } 36 return; 37 } 38 inline void del(int i) { 39 --cnt; 40 // printf("Ans : del : %d \n", i); 41 for(; i <= n; i += i & (-i)) { 42 ta[i]--; 43 } 44 return; 45 } 46 inline int getMax() { 47 int ans = 0, k = cnt, t = pw[n]; 48 while(t >= 0) { 49 if(((ans | (1 << t)) <= n) && ta[ans | (1 << t)] < k) { 50 k -= ta[ans | (1 << t)]; 51 ans |= (1 << t); 52 } 53 t--; 54 } 55 return ans + 1; 56 } 57 } 58 59 namespace ta { 60 int ta[N], cnt; 61 inline void add(int i) { 62 ++cnt; 63 // printf("ta : add : %d \n", i); 64 for(; i <= n; i += i & (-i)) { 65 ta[i]++; 66 } 67 return; 68 } 69 inline void del(int i) { 70 --cnt; 71 // printf("ta : del : %d \n", i); 72 for(; i <= n; i += i & (-i)) { 73 ta[i]--; 74 } 75 return; 76 } 77 inline int getKth(int k) { 78 // printf("ta : Kth %d : ", k); 79 int ans = 0, t = pw[n]; 80 while(t >= 0) { 81 if(((ans | (1 << t)) <= n) && ta[ans | (1 << t)] < k) { 82 k -= ta[ans | (1 << t)]; 83 ans |= (1 << t); 84 } 85 t--; 86 } 87 // printf("%d cnt = %d \n", ans + 1, cnt); 88 return ans + 1; 89 } 90 inline int getSum(int i) { 91 int ans = 0; 92 for(; i; i -= i & (-i)) { 93 ans += ta[i]; 94 } 95 return ans; 96 } 97 } 98 99 struct Ask { 100 int l, r, id; 101 inline bool operator <(const Ask &w) const { 102 if(fr[l] != fr[w.l]) return l < w.l; 103 return r < w.r; 104 } 105 }ask[N]; 106 107 inline void add(int x, int y) { 108 tp++; 109 edge[tp].v = y; 110 edge[tp].nex = e[x]; 111 e[x] = tp; 112 return; 113 } 114 115 void DFS_1(int x, int f) { 116 d[x] = d[f] + 1; 117 // printf("x = %d \n", x); 118 pos[x] = ++num; 119 id[num] = x; 120 pos2[x] = ++num2; 121 ST[num2][0] = x; 122 for(int i = e[x]; i; i = edge[i].nex) { 123 int y = edge[i].v; 124 if(y == f) continue; 125 DFS_1(y, x); 126 ST[++num2][0] = x; 127 } 128 return; 129 } 130 131 inline void prework() { 132 register int i, j; 133 for(i = 2; i <= num2; i++) pw[i] = pw[i >> 1] + 1; 134 for(j = 1; j <= pw[num2]; j++) { 135 for(i = 1; i + (1 << j) - 1 <= num2; i++) { 136 if(d[ST[i][j - 1]] < d[ST[i + (1 << (j - 1))][j - 1]]) 137 ST[i][j] = ST[i][j - 1]; 138 else 139 ST[i][j] = ST[i + (1 << (j - 1))][j - 1]; 140 } 141 } 142 return; 143 } 144 145 inline int lca(int x, int y) { 146 x = pos2[x]; 147 y = pos2[y]; 148 if(x > y) std::swap(x, y); 149 int t = pw[y - x + 1]; 150 if(d[ST[x][t]] < d[ST[y - (1 << t) + 1][t]]) 151 return ST[x][t]; 152 else 153 return ST[y - (1 << t) + 1][t]; 154 } 155 156 inline void add(int x) { 157 // std::cerr << "------------ add " << x << std::endl; 158 ta::add(pos[x]); 159 // std::cerr << "111 \n"; 160 int rk = ta::getSum(pos[x]); 161 // std::cerr << "222 \n"; 162 int y = 0, z = 0; 163 if(rk != 1) { 164 y = id[ta::getKth(rk - 1)]; 165 } 166 if(rk != ta::cnt) { 167 z = id[ta::getKth(rk + 1)]; 168 } 169 // std::cerr << "333 \n"; 170 // out(y); out(z); 171 if(y) Ans::add(d[lca(x, y)]); 172 if(z) Ans::add(d[lca(x, z)]); 173 if(y && z) Ans::del(d[lca(y, z)]); 174 return; 175 } 176 177 inline void del(int x) { 178 // std::cerr << "------------ del " << x << std::endl; 179 int rk = ta::getSum(pos[x]); 180 int y = 0, z = 0; 181 if(rk != 1) { 182 y = id[ta::getKth(rk - 1)]; 183 } 184 if(rk != ta::cnt) { 185 z = id[ta::getKth(rk + 1)]; 186 } 187 if(y) Ans::del(d[lca(x, y)]); 188 if(z) Ans::del(d[lca(x, z)]); 189 if(y && z) Ans::add(d[lca(y, z)]); 190 ta::del(pos[x]); 191 return; 192 } 193 194 int main() { 195 196 freopen("lca.in", "r", stdin); 197 freopen("lca.out", "w", stdout); 198 199 register int i; 200 int m; 201 read(n); read(m); 202 for(int i = 1, x, y; i < n; i++) { 203 read(x); read(y); 204 add(x, y); add(y, x); 205 } 206 DFS_1(1, 0); 207 prework(); 208 int T = n / sqrt(m); 209 for(i = 1; i <= n; i++) { 210 fr[i] = (i - 1) / T + 1; 211 } 212 for(i = 1; i <= m; i++) { 213 read(ask[i].l); read(ask[i].r); 214 ask[i].id = i; 215 } 216 std::sort(ask + 1, ask + m + 1); 217 int l = 1, r = 1; ta::add(1); 218 for(i = 1; i <= m; i++) { 219 /*if(i % 1 == 0) { 220 std::cerr << "i = " << i << std::endl; 221 }*/ 222 // printf("i = %d [%d %d] ask [%d %d] \n", i, l, r, ask[i].l, ask[i].r); 223 while(ask[i].l < l) { 224 add(--l); 225 } 226 while(r < ask[i].r) { 227 add(++r); 228 } 229 while(l < ask[i].l) { 230 del(l++); 231 } 232 while(ask[i].r < r) { 233 del(r--); 234 } 235 // printf("Ans = %d \n", Ans::getMax()); 236 ans[ask[i].id] = Ans::getMax(); 237 } 238 for(i = 1; i <= m; i++) { 239 printf("%d\n", ans[i]); 240 } 241 return 0; 242 }