猫树模板

参考博客:
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');
	}
}
posted @ 2020-06-08 21:43  Cold_Chair  阅读(208)  评论(0编辑  收藏  举报