洛谷 P4592 / LOJ 2577「TJOI2018」异或

洛谷传送门

LOJ 传送门

思路

显然可持久化 01 trie。

询问一,由于一个结点的子树可以映射到 \(\mathrm{dfs}\) 序上一段连续的区间,因此可以对 \(\mathrm{dfn}\) 区间建可持久化 01 trie,查询直接做就可以。

询问二,用树剖会多一个 \(\log\),很垃圾。考虑差分思想,\(x\)\(y\) 的简单路径相当于 \(x\) 到根结点的路径加上 \(y\) 到根结点的路径,减去 \(\mathrm{lca}(x,y)\) 到根结点的路径再减去 \(fa_{\mathrm{lca}(x,y)}\) 到根结点的路径。对每个结点到根结点的链建可持久化 01 trie,查询时差分即可。

时间复杂度 \(O(n \log w)\)

代码

code
/*

p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 100100;
const int maxm = 10000000;

int n, m, a[maxn], head[maxn], len;
int rt1[maxn], rt2[maxn], ch[maxm][2], tsz[maxm], totn;
int dp[maxn], sz[maxn], son[maxn], fa[maxn];
int top[maxn], st[maxn], times, ed[maxn];
bool vis[maxn];

struct edge {
	int to, next;
} edges[maxn << 1];

void add_edge(int u, int v) {
	edges[++len].to = v;
	edges[len].next = head[u];
	head[u] = len;
}

int insert(int rt, int x, int d) {
	int p = ++totn;
	ch[p][0] = ch[rt][0];
	ch[p][1] = ch[rt][1];
	tsz[p] = tsz[rt] + 1;
	if (d >= 0) {
		int k = ((x >> d) & 1);
		ch[p][k] = insert(ch[p][k], x, d - 1);
	}
	return p;
}

int query(int p, int q, int x, int d) {
	if (d == -1) {
		return 0;
	}
	int k = ((x >> d) & 1);
	if (tsz[ch[q][k ^ 1]] - tsz[ch[p][k ^ 1]] > 0) {
		return (1 << d) | query(ch[p][k ^ 1], ch[q][k ^ 1], x, d - 1);
	} else {
		return query(ch[p][k], ch[q][k], x, d - 1);
	}
}

int dfs(int u, int f, int d) {
	dp[u] = d;
	sz[u] = 1;
	fa[u] = f;
	st[u] = ++times;
	rt1[times] = insert(rt1[times - 1], a[u], 29);
	int maxson = -1;
	for (int i = head[u]; i; i = edges[i].next) {
		int v = edges[i].to;
		if (v == f) {
			continue;
		}
		rt2[v] = insert(rt2[u], a[v], 29);
		sz[u] += dfs(v, u, d + 1);
		if (sz[v] > maxson) {
			son[u] = v;
			maxson = sz[v];
		}
	}
	ed[u] = times;
	return sz[u];
}

void dfs2(int u, int tp) {
	top[u] = tp;
	vis[u] = 1;
	if (!son[u]) {
		return;
	}
	dfs2(son[u], tp);
	for (int i = head[u]; i; i = edges[i].next) {
		int v = edges[i].to;
		if (!vis[v]) {
			dfs2(v, v);
		}
	}
}

int querylca(int x, int y) {
	while (top[x] != top[y]) {
		if (dp[top[x]] < dp[top[y]]) {
			swap(x, y);
		}
		x = fa[top[x]];
	}
	if (dp[x] > dp[y]) {
		swap(x, y);
	}
	return x;
}

void solve() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
	}
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		add_edge(u, v);
		add_edge(v, u);
	}
	dfs(1, 0, 1);
	dfs2(1, 1);
	while (m--) {
		int op, x, y, z;
		scanf("%d%d%d", &op, &x, &y);
		if (op == 1) {
			printf("%d\n", query(rt1[st[x] - 1], rt1[ed[x]], y, 29));
		} else {
			scanf("%d", &z);
			int lca = querylca(x, y);
			int k = fa[lca];
			printf("%d\n", max(query(rt2[k], rt2[x], z, 29), query(rt2[lca], rt2[y], z, 29)));
		}
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2022-07-19 14:04  zltzlt  阅读(28)  评论(0编辑  收藏  举报