猫树模板
参考博客:
http://immortalco.blog.uoj.ac/blog/2102
https://www.cnblogs.com/Judge/p/10475728.html
板题:
https://www.luogu.com.cn/problem/P3865
注意点:
-
猫树的语处理的数组的存法:同一深度的区间互不相交,所以记二维数组,第一维是深度,第二维是位置。
-
猫树的核心在于快速求lca,所以需要把线段树长度搞成\(2^{tp}\),这样\(x\)在线段树的编号就是\(x+2^{tp}\),两个点的lca就是树上编号的lcp,可以通过预处理\(log_2\)来快速处理。
-
预处理的\(log_2\)数组必须是两倍于最大的\(2^{tp}\),因为当\(x,y\)相同时,会要求\(log_2(x+2^{tp})\),这个数是超过\(2^{tp+1}\)的。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
#define gc getchar
template<class T> void read(T &x) {
char c = ' '; int f = 1; x = 0;
while(c != '-' && (c < '0' || c > '9')) c = gc();
if(c == '-') c = gc(), f = -1;
for(; c >= '0' && c <= '9'; c = gc()) x = x * 10 + c - '0';
x *= f;
}
#define pc putchar
template<class T> void write(T x) {
int d[30], d0 = 0;
if(!x) d[d0 = 1] = 0; else {
for(; x; x /= 10) d[++ d0] = x % 10;
}
while(d0) pc(d[d0 --] + '0');
}
const int N = (1 << 17) + 5;
int lg2[N * 2];
int n, m;
int tp;
int a[N];
#define i0 i + i
#define i1 i + i + 1
int f[18][N];
void dg(int i, int x, int y) {
int D = lg2[i];
if(x == y) {
f[D][x] = a[x];
return;
}
int m = x + y >> 1;
dg(i0, x, m); dg(i1, m + 1, y);
int v = 0;
fd(j, m, x) v = max(v, a[j]), f[D][j] = v;
v = 0;
fo(j, m + 1, y) v = max(v, a[j]), f[D][j] = v;
}
int main() {
lg2[0] = -1;
fo(i, 2, 1 << 18) lg2[i] = lg2[i / 2] + 1;
scanf("%d %d", &n, &m);
fo(i, 1, n) read(a[i]);
while(1 << (++ tp) <= n);
dg(1, 0, (1 << tp) - 1);
fo(ii, 1, m) {
int x, y; read(x); read(y);
int u = x + (1 << tp), v = y + (1 << tp);
int D = lg2[u >> (lg2[u ^ v] + 1)];
write(max(f[D][x], f[D][y])); pc('\n');
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址